From da15968c4ee7354f455f7956b7110313cf19118f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Nov 2023 21:00:56 +0000 Subject: [PATCH 001/124] Bump openssl in /old_code/twitch-ingestion-client Bumps [openssl](https://github.com/sfackler/rust-openssl) from 0.10.32 to 0.10.60. - [Release notes](https://github.com/sfackler/rust-openssl/releases) - [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.32...openssl-v0.10.60) --- updated-dependencies: - dependency-name: openssl dependency-type: indirect ... Signed-off-by: dependabot[bot] --- old_code/twitch-ingestion-client/Cargo.lock | 37 +++++++++++++++------ 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/old_code/twitch-ingestion-client/Cargo.lock b/old_code/twitch-ingestion-client/Cargo.lock index d0940e3100..2f7105417c 100644 --- a/old_code/twitch-ingestion-client/Cargo.lock +++ b/old_code/twitch-ingestion-client/Cargo.lock @@ -203,6 +203,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + [[package]] name = "blocking" version = "1.0.2" @@ -420,7 +426,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" dependencies = [ - "bitflags", + "bitflags 1.2.1", "fuchsia-zircon-sys", ] @@ -867,18 +873,30 @@ checksum = "4ad167a2f54e832b82dbe003a046280dceffe5227b5f79e08e363a29638cfddd" [[package]] name = "openssl" -version = "0.10.32" +version = "0.10.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038d43985d1ddca7a9900630d8cd031b56e4794eecc2e9ea39dd17aa04399a70" +checksum = "79a4c6c3a2b158f7f8f2a2fc5a969fa3a068df6fc9dbb4a43845436e3af7c800" dependencies = [ - "bitflags", + "bitflags 2.4.1", "cfg-if 1.0.0", "foreign-types", - "lazy_static", "libc", + "once_cell", + "openssl-macros", "openssl-sys", ] +[[package]] +name = "openssl-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "openssl-probe" version = "0.1.2" @@ -887,11 +905,10 @@ checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" [[package]] name = "openssl-sys" -version = "0.9.60" +version = "0.9.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "921fc71883267538946025deffb622905ecad223c28efbfdef9bb59a0175f3e6" +checksum = "3812c071ba60da8b5677cc12bcb1d42989a65553772897a7e0355545a819838f" dependencies = [ - "autocfg", "cc", "libc", "pkg-config", @@ -1122,7 +1139,7 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9" dependencies = [ - "bitflags", + "bitflags 1.2.1", ] [[package]] @@ -1217,7 +1234,7 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6af1b6204f89cf0069736daf8b852573e3bc34898eee600e95d3dd855c12e81" dependencies = [ - "bitflags", + "bitflags 1.2.1", "core-foundation", "core-foundation-sys", "libc", From 0128134d3d86056a57a713ddf1c5ba18879c044e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Nov 2023 21:02:17 +0000 Subject: [PATCH 002/124] Bump openssl from 0.10.33 to 0.10.60 in /old_code/pubsub-enricher Bumps [openssl](https://github.com/sfackler/rust-openssl) from 0.10.33 to 0.10.60. - [Release notes](https://github.com/sfackler/rust-openssl/releases) - [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.33...openssl-v0.10.60) --- updated-dependencies: - dependency-name: openssl dependency-type: indirect ... Signed-off-by: dependabot[bot] --- old_code/pubsub-enricher/Cargo.lock | 35 +++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/old_code/pubsub-enricher/Cargo.lock b/old_code/pubsub-enricher/Cargo.lock index 9abc97549e..f9b9184af9 100644 --- a/old_code/pubsub-enricher/Cargo.lock +++ b/old_code/pubsub-enricher/Cargo.lock @@ -205,6 +205,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + [[package]] name = "blocking" version = "1.0.2" @@ -464,7 +470,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" dependencies = [ - "bitflags", + "bitflags 1.2.1", "fuchsia-zircon-sys", ] @@ -1031,18 +1037,30 @@ checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" [[package]] name = "openssl" -version = "0.10.33" +version = "0.10.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a61075b62a23fef5a29815de7536d940aa35ce96d18ce0cc5076272db678a577" +checksum = "79a4c6c3a2b158f7f8f2a2fc5a969fa3a068df6fc9dbb4a43845436e3af7c800" dependencies = [ - "bitflags", + "bitflags 2.4.1", "cfg-if 1.0.0", "foreign-types", "libc", "once_cell", + "openssl-macros", "openssl-sys", ] +[[package]] +name = "openssl-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "openssl-probe" version = "0.1.2" @@ -1051,11 +1069,10 @@ checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" [[package]] name = "openssl-sys" -version = "0.9.61" +version = "0.9.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "313752393519e876837e09e1fa183ddef0be7735868dced3196f4472d536277f" +checksum = "3812c071ba60da8b5677cc12bcb1d42989a65553772897a7e0355545a819838f" dependencies = [ - "autocfg", "cc", "libc", "pkg-config", @@ -1337,7 +1354,7 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8270314b5ccceb518e7e578952f0b72b88222d02e8f77f5ecf7abbb673539041" dependencies = [ - "bitflags", + "bitflags 1.2.1", ] [[package]] @@ -1481,7 +1498,7 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3670b1d2fdf6084d192bc71ead7aabe6c06aa2ea3fbd9cc3ac111fa5c2b1bd84" dependencies = [ - "bitflags", + "bitflags 1.2.1", "core-foundation", "core-foundation-sys", "libc", From 93ebe101f34c510a29d59e9d3e74a9c0ef18a3d9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Nov 2023 21:03:53 +0000 Subject: [PATCH 003/124] Bump openssl in /old_code/twitter-ingestion-client Bumps [openssl](https://github.com/sfackler/rust-openssl) from 0.10.34 to 0.10.60. - [Release notes](https://github.com/sfackler/rust-openssl/releases) - [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.34...openssl-v0.10.60) --- updated-dependencies: - dependency-name: openssl dependency-type: indirect ... Signed-off-by: dependabot[bot] --- old_code/twitter-ingestion-client/Cargo.lock | 35 +++++++++++++++----- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/old_code/twitter-ingestion-client/Cargo.lock b/old_code/twitter-ingestion-client/Cargo.lock index 7c8b31c916..ca62dba895 100644 --- a/old_code/twitter-ingestion-client/Cargo.lock +++ b/old_code/twitter-ingestion-client/Cargo.lock @@ -193,6 +193,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + [[package]] name = "block-buffer" version = "0.9.0" @@ -505,7 +511,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" dependencies = [ - "bitflags", + "bitflags 1.2.1", "fuchsia-zircon-sys", ] @@ -1063,18 +1069,30 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.34" +version = "0.10.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d7830286ad6a3973c0f1d9b73738f69c76b739301d0229c4b96501695cbe4c8" +checksum = "79a4c6c3a2b158f7f8f2a2fc5a969fa3a068df6fc9dbb4a43845436e3af7c800" dependencies = [ - "bitflags", + "bitflags 2.4.1", "cfg-if 1.0.0", "foreign-types", "libc", "once_cell", + "openssl-macros", "openssl-sys", ] +[[package]] +name = "openssl-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "openssl-probe" version = "0.1.2" @@ -1083,11 +1101,10 @@ checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" [[package]] name = "openssl-sys" -version = "0.9.63" +version = "0.9.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6b0d6fb7d80f877617dfcb014e605e2b5ab2fb0afdf27935219bb6bd984cb98" +checksum = "3812c071ba60da8b5677cc12bcb1d42989a65553772897a7e0355545a819838f" dependencies = [ - "autocfg", "cc", "libc", "pkg-config", @@ -1379,7 +1396,7 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "742739e41cd49414de871ea5e549afb7e2a3ac77b589bcbebe8c82fab37147fc" dependencies = [ - "bitflags", + "bitflags 1.2.1", ] [[package]] @@ -1468,7 +1485,7 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3670b1d2fdf6084d192bc71ead7aabe6c06aa2ea3fbd9cc3ac111fa5c2b1bd84" dependencies = [ - "bitflags", + "bitflags 1.2.1", "core-foundation", "core-foundation-sys", "libc", From a3ab6347255c1bbf993329be90087a506ca5fdb0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Nov 2023 21:11:08 +0000 Subject: [PATCH 004/124] Bump openssl in /old_code/twitch-tts-desktop-client Bumps [openssl](https://github.com/sfackler/rust-openssl) from 0.10.36 to 0.10.60. - [Release notes](https://github.com/sfackler/rust-openssl/releases) - [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.36...openssl-v0.10.60) --- updated-dependencies: - dependency-name: openssl dependency-type: indirect ... Signed-off-by: dependabot[bot] --- old_code/twitch-tts-desktop-client/Cargo.lock | 33 ++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/old_code/twitch-tts-desktop-client/Cargo.lock b/old_code/twitch-tts-desktop-client/Cargo.lock index 959c7d0729..1e8538ee1e 100644 --- a/old_code/twitch-tts-desktop-client/Cargo.lock +++ b/old_code/twitch-tts-desktop-client/Cargo.lock @@ -77,6 +77,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + [[package]] name = "block-buffer" version = "0.9.0" @@ -645,18 +651,30 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openssl" -version = "0.10.36" +version = "0.10.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d9facdb76fec0b73c406f125d44d86fdad818d66fef0531eec9233ca425ff4a" +checksum = "79a4c6c3a2b158f7f8f2a2fc5a969fa3a068df6fc9dbb4a43845436e3af7c800" dependencies = [ - "bitflags", + "bitflags 2.4.1", "cfg-if", "foreign-types", "libc", "once_cell", + "openssl-macros", "openssl-sys", ] +[[package]] +name = "openssl-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "openssl-probe" version = "0.1.4" @@ -665,11 +683,10 @@ checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" [[package]] name = "openssl-sys" -version = "0.9.67" +version = "0.9.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69df2d8dfc6ce3aaf44b40dec6f487d5a886516cf6879c49e98e0710f310a058" +checksum = "3812c071ba60da8b5677cc12bcb1d42989a65553772897a7e0355545a819838f" dependencies = [ - "autocfg", "cc", "libc", "pkg-config", @@ -808,7 +825,7 @@ version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -975,7 +992,7 @@ version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "525bc1abfda2e1998d152c45cf13e696f76d0a4972310b22fac1658b05df7c87" dependencies = [ - "bitflags", + "bitflags 1.3.2", "core-foundation", "core-foundation-sys", "libc", From 133ccff348ba127ca52f7300b4107f105148722f Mon Sep 17 00:00:00 2001 From: kasisnu <5044120+kasisnu@users.noreply.github.com> Date: Wed, 29 Nov 2023 17:12:22 +0530 Subject: [PATCH 005/124] update media file visibilty handler --- .../http_server/endpoints/media_files/mod.rs | 1 + .../media_files/update_media_file.rs | 154 ++++++++++++++++++ .../service/web/storyteller_web/src/routes.rs | 5 + 3 files changed, 160 insertions(+) create mode 100644 crates/service/web/storyteller_web/src/http_server/endpoints/media_files/update_media_file.rs diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/mod.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/mod.rs index 014fa68854..4f010c38fe 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/mod.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/mod.rs @@ -1,3 +1,4 @@ pub mod drain_multipart_request; pub mod get_media_file; pub mod delete_media_file; +pub mod update_media_file; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/update_media_file.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/update_media_file.rs new file mode 100644 index 0000000000..4d099b8bbf --- /dev/null +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/update_media_file.rs @@ -0,0 +1,154 @@ +use std::fmt; +use std::sync::Arc; + +use actix_web::{HttpRequest, HttpResponse, web}; +use actix_web::error::ResponseError; +use actix_web::http::StatusCode; +use actix_web::web::Path; +use log::{error, log, warn}; +use enums::common::visibility::Visibility; + +use http_server_common::request::get_request_ip::get_request_ip; +use http_server_common::response::response_success_helpers::simple_json_success; +use http_server_common::response::serialize_as_json_error::serialize_as_json_error; +use mysql_queries::queries::media_files::get_media_file::get_media_file; +use mysql_queries::queries::media_files::update_media_file::{update_media_file, UpdateMediaFileArgs}; +use tokens::tokens::media_files::MediaFileToken; + +use crate::server_state::ServerState; + +#[derive(Deserialize)] +pub struct UpdateMediaFileRequest { + pub creator_set_visibility: Option, +} + +#[derive(Serialize)] +pub struct UpdateMediaFileResponse { + pub success: bool, +} + +/// For the URL PathInfo +#[derive(Deserialize)] +pub struct UpdateMediaFilePathInfo { + token: MediaFileToken, +} + +// =============== Error Response =============== + +#[derive(Debug, Serialize)] +pub enum UpdateMediaFileError { + BadInput(String), + NotFound, + NotAuthorized, + ServerError, +} + +impl ResponseError for UpdateMediaFileError { + fn status_code(&self) -> StatusCode { + match *self { + UpdateMediaFileError::BadInput(_) => StatusCode::BAD_REQUEST, + UpdateMediaFileError::NotFound => StatusCode::NOT_FOUND, + UpdateMediaFileError::NotAuthorized => StatusCode::UNAUTHORIZED, + UpdateMediaFileError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, + } + } + + fn error_response(&self) -> HttpResponse { + serialize_as_json_error(self) + } +} + +// NB: Not using derive_more::Display since Clion doesn't understand it. +impl fmt::Display for UpdateMediaFileError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", self) + } +} + +// =============== Handler =============== + +pub async fn update_media_file_handler( + http_request: HttpRequest, + path: Path, + request: web::Json, + server_state: web::Data>) -> Result +{ + let maybe_user_session = server_state + .session_checker + .maybe_get_user_session(&http_request, &server_state.mysql_pool) + .await + .map_err(|e| { + warn!("Session checker error: {:?}", e); + UpdateMediaFileError::ServerError + })?; + + let user_session = match maybe_user_session { + Some(session) => session, + None => { + warn!("not logged in"); + return Err(UpdateMediaFileError::NotAuthorized); + } + }; + + let media_file_token = path.token.clone(); + let is_mod = user_session.can_ban_users; + + let media_file_lookup_result = get_media_file( + &path.token, + is_mod, + &server_state.mysql_pool, + ).await; + + let media_file = match media_file_lookup_result { + Ok(Some(media_file)) => media_file, + Ok(None) => { + warn!("MediaFile not found: {:?}", media_file_token); + return Err(UpdateMediaFileError::NotFound); + }, + Err(err) => { + warn!("Error looking up media_file: {:?}", err); + return Err(UpdateMediaFileError::ServerError); + } + }; + + let is_creator = media_file.maybe_creator_user_token + .is_some_and(|t| t.as_str() == &user_session.user_token); + + if !is_creator && !is_mod { + warn!("user is not allowed to edit this media_file: {}", user_session.user_token); + return Err(UpdateMediaFileError::NotAuthorized); + } + + let mut creator_set_visibility = Visibility::Public; + + + if let Some(visibility) = request.creator_set_visibility.as_deref() { + creator_set_visibility = Visibility::from_str(visibility) + .map_err(|_| UpdateMediaFileError::BadInput("bad record visibility".to_string()))?; + } + + let ip_address = get_request_ip(&http_request); + let mut maybe_mod_user_token = None; + + if is_mod { + maybe_mod_user_token = Some(user_session.user_token.clone()); + } + let query_result = update_media_file( + UpdateMediaFileArgs { + media_file_token: &media_file_token.clone(), + creator_set_visibility: &creator_set_visibility, + maybe_mod_user_token: maybe_mod_user_token.as_deref(), + mysql_pool: &server_state.mysql_pool + } + ).await; + + match query_result { + Ok(_) => {}, + Err(err) => { + warn!("Update MediaFile DB error: {:?}", err); + return Err(UpdateMediaFileError::ServerError); + } + }; + + Ok(simple_json_success()) +} diff --git a/crates/service/web/storyteller_web/src/routes.rs b/crates/service/web/storyteller_web/src/routes.rs index 9b6f920061..c1cdc543eb 100644 --- a/crates/service/web/storyteller_web/src/routes.rs +++ b/crates/service/web/storyteller_web/src/routes.rs @@ -43,6 +43,7 @@ use crate::http_server::endpoints::investor_demo::enable_demo_mode_handler::enab use crate::http_server::endpoints::leaderboard::get_leaderboard::leaderboard_handler; use crate::http_server::endpoints::media_files::delete_media_file::delete_media_file_handler; use crate::http_server::endpoints::media_files::get_media_file::get_media_file_handler; +use crate::http_server::endpoints::media_files::update_media_file::update_media_file_handler; use crate::http_server::endpoints::media_uploads::list_user_media_uploads_of_type::list_user_media_uploads_of_type_handler; use crate::http_server::endpoints::media_uploads::upload_audio::upload_audio_handler; use crate::http_server::endpoints::media_uploads::upload_image::upload_image_handler; @@ -1000,6 +1001,10 @@ fn add_media_file_routes (app: App) -> App .route(web::delete().to(delete_media_file_handler)) .route(web::head().to(|| HttpResponse::Ok())) ) + .service(web::resource("/file/{token}/update") + .route(web::post().to(update_media_file_handler)) + .route(web::head().to(|| HttpResponse::Ok())) + ) ) } From d39962491f596f09fa011f6745ae45e8e75aba5d Mon Sep 17 00:00:00 2001 From: salt Date: Thu, 7 Dec 2023 18:36:51 -0800 Subject: [PATCH 006/124] fix some warnings (mostly unnecessary mut) --- .../src/searches/search_tts_models.rs | 2 +- .../list_available_email_sender_jobs.rs | 2 +- .../job/list_available_generic_inference_jobs.rs | 2 +- .../job/mark_generic_inference_job_failure.rs | 2 +- .../src/queries/media_files/update_media_file.rs | 2 +- .../model_categories/list_categories_query_builder.rs | 6 +++--- .../src/queries/model_weights/update_weight.rs | 2 +- .../list_trending_tts_models.rs | 2 +- .../list_assigned_tts_categories_query_builder.rs | 2 +- .../tts/tts_download_jobs/tts_download_job_queries.rs | 2 +- .../tts/tts_results/list_tts_results_query_builder.rs | 2 +- .../twitch_event_rules/reorder_twitch_event_rules.rs | 2 +- .../src/queries/twitch/twitch_oauth/find.rs | 2 +- .../src/queries/users/user/list_users_query_builder.rs | 10 +++++----- 14 files changed, 20 insertions(+), 20 deletions(-) diff --git a/crates/lib/elasticsearch_schema/src/searches/search_tts_models.rs b/crates/lib/elasticsearch_schema/src/searches/search_tts_models.rs index 1ae2cc18ca..30055f1774 100644 --- a/crates/lib/elasticsearch_schema/src/searches/search_tts_models.rs +++ b/crates/lib/elasticsearch_schema/src/searches/search_tts_models.rs @@ -27,7 +27,7 @@ pub async fn search_tts_models( let mut response_json = search_response.json::().await?; - let mut hits = response_json.get_mut("hits") + let hits = response_json.get_mut("hits") .map(|hits| hits.take()); let hits = hits.map(|mut hits| { diff --git a/crates/lib/mysql_queries/src/queries/email_sender_jobs/list_available_email_sender_jobs.rs b/crates/lib/mysql_queries/src/queries/email_sender_jobs/list_available_email_sender_jobs.rs index 55669b4422..8420295eb5 100644 --- a/crates/lib/mysql_queries/src/queries/email_sender_jobs/list_available_email_sender_jobs.rs +++ b/crates/lib/mysql_queries/src/queries/email_sender_jobs/list_available_email_sender_jobs.rs @@ -167,7 +167,7 @@ FROM email_sender_jobs"#.to_string(); LIMIT ? "#); - let mut query = sqlx::query_as::<_, AvailableEmailSenderJobRawInternal>(&query) + let query = sqlx::query_as::<_, AvailableEmailSenderJobRawInternal>(&query) .bind(args.is_debug_worker) .bind(args.num_records); diff --git a/crates/lib/mysql_queries/src/queries/generic_inference/job/list_available_generic_inference_jobs.rs b/crates/lib/mysql_queries/src/queries/generic_inference/job/list_available_generic_inference_jobs.rs index 4cb3b5fa7e..1f72d607cb 100644 --- a/crates/lib/mysql_queries/src/queries/generic_inference/job/list_available_generic_inference_jobs.rs +++ b/crates/lib/mysql_queries/src/queries/generic_inference/job/list_available_generic_inference_jobs.rs @@ -336,7 +336,7 @@ FROM generic_inference_jobs"#.to_string(); LIMIT ? "#); - let mut query = sqlx::query_as::<_, AvailableInferenceJobRawInternal>(&query) + let query = sqlx::query_as::<_, AvailableInferenceJobRawInternal>(&query) .bind(args.is_debug_worker) .bind(args.num_records); diff --git a/crates/lib/mysql_queries/src/queries/generic_inference/job/mark_generic_inference_job_failure.rs b/crates/lib/mysql_queries/src/queries/generic_inference/job/mark_generic_inference_job_failure.rs index a1df90a95a..5a3ea2fb6d 100644 --- a/crates/lib/mysql_queries/src/queries/generic_inference/job/mark_generic_inference_job_failure.rs +++ b/crates/lib/mysql_queries/src/queries/generic_inference/job/mark_generic_inference_job_failure.rs @@ -20,7 +20,7 @@ pub async fn mark_generic_inference_job_failure( // statuses: "attempt_failed", "complete_failure", "dead" let mut next_status = "attempt_failed"; - let mut maybe_public_failure_reason = maybe_public_failure_reason.map(|reason| { + let maybe_public_failure_reason = maybe_public_failure_reason.map(|reason| { let mut reason = reason.trim().to_string(); reason.truncate(512); // Max length of column is 512 reason diff --git a/crates/lib/mysql_queries/src/queries/media_files/update_media_file.rs b/crates/lib/mysql_queries/src/queries/media_files/update_media_file.rs index 10ea2024c4..8faa739b0f 100644 --- a/crates/lib/mysql_queries/src/queries/media_files/update_media_file.rs +++ b/crates/lib/mysql_queries/src/queries/media_files/update_media_file.rs @@ -14,7 +14,7 @@ pub struct UpdateMediaFileArgs<'a> { pub async fn update_media_file(args: UpdateMediaFileArgs<'_>) -> AnyhowResult<()>{ // TODO: enforce checks for idempotency token - let mut transaction = args.mysql_pool.begin().await?; + let transaction = args.mysql_pool.begin().await?; let query_result = sqlx::query!( r#" UPDATE media_files diff --git a/crates/lib/mysql_queries/src/queries/model_categories/list_categories_query_builder.rs b/crates/lib/mysql_queries/src/queries/model_categories/list_categories_query_builder.rs index 136751050d..845b7e60f1 100644 --- a/crates/lib/mysql_queries/src/queries/model_categories/list_categories_query_builder.rs +++ b/crates/lib/mysql_queries/src/queries/model_categories/list_categories_query_builder.rs @@ -184,7 +184,7 @@ impl ListCategoriesQueryBuilder { query = query.bind(model_type); } - let mut results = query.fetch_all(&mut **mysql_connection) + let results = query.fetch_all(&mut **mysql_connection) .await?; Ok(results) @@ -239,7 +239,7 @@ LEFT OUTER JOIN users let mut query = "".to_string(); - if let Some(username) = self.scope_creator_user_token.as_deref() { + if let Some(_username) = self.scope_creator_user_token.as_deref() { if !first_predicate_added { query.push_str(" WHERE model_categories.creator_user_token = ?"); first_predicate_added = true; @@ -248,7 +248,7 @@ LEFT OUTER JOIN users } } - if let Some(model_type) = self.scope_model_type.as_deref() { + if let Some(_model_type) = self.scope_model_type.as_deref() { if !first_predicate_added { query.push_str(" WHERE model_categories.model_type = ?"); first_predicate_added = true; diff --git a/crates/lib/mysql_queries/src/queries/model_weights/update_weight.rs b/crates/lib/mysql_queries/src/queries/model_weights/update_weight.rs index cbe0ba55d7..eb95ef40d7 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/update_weight.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/update_weight.rs @@ -16,7 +16,7 @@ pub struct UpdateWeightArgs<'a> { } pub async fn update_weights(args: UpdateWeightArgs<'_>) -> AnyhowResult<()> { - let mut transaction = args.mysql_pool.begin().await?; + let transaction = args.mysql_pool.begin().await?; let query_result = sqlx ::query!( diff --git a/crates/lib/mysql_queries/src/queries/trending_model_analytics/list_trending_tts_models.rs b/crates/lib/mysql_queries/src/queries/trending_model_analytics/list_trending_tts_models.rs index e81d9c339a..5ec24e4eeb 100644 --- a/crates/lib/mysql_queries/src/queries/trending_model_analytics/list_trending_tts_models.rs +++ b/crates/lib/mysql_queries/src/queries/trending_model_analytics/list_trending_tts_models.rs @@ -63,7 +63,7 @@ pub async fn list_trending_tts_models( ]; let query = query_parts.join(" UNION "); - let mut query = sqlx::query_as::<_, RawTrendingModel>(&query); + let query = sqlx::query_as::<_, RawTrendingModel>(&query); let results = query.fetch_all(&mut **mysql_connection).await?; diff --git a/crates/lib/mysql_queries/src/queries/tts/tts_category_assignments/list_assigned_tts_categories_query_builder.rs b/crates/lib/mysql_queries/src/queries/tts/tts_category_assignments/list_assigned_tts_categories_query_builder.rs index 23dabea29c..f5bd643639 100644 --- a/crates/lib/mysql_queries/src/queries/tts/tts_category_assignments/list_assigned_tts_categories_query_builder.rs +++ b/crates/lib/mysql_queries/src/queries/tts/tts_category_assignments/list_assigned_tts_categories_query_builder.rs @@ -159,7 +159,7 @@ impl ListAssignedTtsCategoriesQueryBuilder { // NB: Model token is always used for scoping. query = query.bind(&self.scope_tts_model_token); - let mut results = query.fetch_all(&mut **mysql_connection) + let results = query.fetch_all(&mut **mysql_connection) .await?; Ok(results) diff --git a/crates/lib/mysql_queries/src/queries/tts/tts_download_jobs/tts_download_job_queries.rs b/crates/lib/mysql_queries/src/queries/tts/tts_download_jobs/tts_download_job_queries.rs index 490493cf27..0a97d15436 100644 --- a/crates/lib/mysql_queries/src/queries/tts/tts_download_jobs/tts_download_job_queries.rs +++ b/crates/lib/mysql_queries/src/queries/tts/tts_download_jobs/tts_download_job_queries.rs @@ -192,7 +192,7 @@ pub async fn mark_tts_upload_job_done( { let status = if success { "complete_success" } else { "complete_failure" }; - let query_result = sqlx::query!( + let _query_result = sqlx::query!( r#" UPDATE tts_model_upload_jobs SET diff --git a/crates/lib/mysql_queries/src/queries/tts/tts_results/list_tts_results_query_builder.rs b/crates/lib/mysql_queries/src/queries/tts/tts_results/list_tts_results_query_builder.rs index d11c2b921c..0ed9b446a7 100644 --- a/crates/lib/mysql_queries/src/queries/tts/tts_results/list_tts_results_query_builder.rs +++ b/crates/lib/mysql_queries/src/queries/tts/tts_results/list_tts_results_query_builder.rs @@ -268,7 +268,7 @@ LEFT OUTER JOIN users } } - if let Some(username) = self.scope_creator_username.as_deref() { + if let Some(_username) = self.scope_creator_username.as_deref() { if !first_predicate_added { query.push_str(" WHERE users.username = ?"); first_predicate_added = true; diff --git a/crates/lib/mysql_queries/src/queries/twitch/twitch_event_rules/reorder_twitch_event_rules.rs b/crates/lib/mysql_queries/src/queries/twitch/twitch_event_rules/reorder_twitch_event_rules.rs index 1842de1a2a..f2cafbbef1 100644 --- a/crates/lib/mysql_queries/src/queries/twitch/twitch_event_rules/reorder_twitch_event_rules.rs +++ b/crates/lib/mysql_queries/src/queries/twitch/twitch_event_rules/reorder_twitch_event_rules.rs @@ -93,7 +93,7 @@ SET "#, query_inner_positions, query_inner_ip_addresses, user_token, rule_tokens); // NB: This, unfortunately, cannot be statically checked. - let mut query = sqlx::query(&query); + let query = sqlx::query(&query); let result = query.execute(mysql_pool).await; diff --git a/crates/lib/mysql_queries/src/queries/twitch/twitch_oauth/find.rs b/crates/lib/mysql_queries/src/queries/twitch/twitch_oauth/find.rs index 55d93b4246..015e52f891 100644 --- a/crates/lib/mysql_queries/src/queries/twitch/twitch_oauth/find.rs +++ b/crates/lib/mysql_queries/src/queries/twitch/twitch_oauth/find.rs @@ -145,7 +145,7 @@ impl TwitchOauthTokenFinder { query = query.bind(twitch_username); } - let mut result = query.fetch_optional(mysql_pool).await; + let result = query.fetch_optional(mysql_pool).await; match result { Ok(Some(record)) => { diff --git a/crates/lib/mysql_queries/src/queries/users/user/list_users_query_builder.rs b/crates/lib/mysql_queries/src/queries/users/user/list_users_query_builder.rs index e00ed36aa6..d9f623e33e 100644 --- a/crates/lib/mysql_queries/src/queries/users/user/list_users_query_builder.rs +++ b/crates/lib/mysql_queries/src/queries/users/user/list_users_query_builder.rs @@ -65,10 +65,10 @@ impl ListUsersQueryBuilder { let internal_results = self.internal_query(mysql_pool).await?; - let mut first_id = internal_results.first() + let first_id = internal_results.first() .map(|raw_result| raw_result.user_id); - let mut last_id = internal_results.last() + let last_id = internal_results.last() .map(|raw_result| raw_result.user_id); let users = internal_results @@ -106,17 +106,17 @@ impl ListUsersQueryBuilder { ) -> AnyhowResult> { let query = self.build_query_string(); - let mut query = sqlx::query_as::<_, UserForListRaw>(&query); + let query = sqlx::query_as::<_, UserForListRaw>(&query); - let mut results = query.fetch_all(mysql_pool) + let results = query.fetch_all(mysql_pool) .await?; Ok(results) } pub fn build_query_string(&self) -> String { - let mut query_string = r#" + let query_string = r#" SELECT id as user_id, token as user_token, From 5971d95a8052bbd04a8f88262ae415c9bd320f1c Mon Sep 17 00:00:00 2001 From: kasisnu <5044120+kasisnu@users.noreply.github.com> Date: Mon, 11 Dec 2023 18:57:55 +0530 Subject: [PATCH 007/124] Rename favorites -> user_bookmarks, add new table --- ...ebbdb76045ad26aeb1c517a54c296bf31087.json} | 8 +- ...c6fa65ede80d9efcaa4996694ce32c12cc0c.json} | 6 +- ...0b5a04e33d7c6b9c38bef96f275b064a12386.json | 12 ++ ...04d73b9f4a649098fc0ba78cbc20cfde12437.json | 12 -- ...dfe33c94b61046c30940f55cdc73789f94041.json | 12 -- ...1efd0cfa6b20899151f9e7f1a122c1f7a70e.json} | 8 +- ...c352624b79bd4e097f57db5ad59f53fd66995.json | 12 ++ ...449362c074fc2397e23ecd175b6a0425b16b.json} | 8 +- .../down.sql | 5 + .../up.sql | 46 +++++++ .../favorites/favorite_entity_type.rs | 128 ------------------ .../enums/src/by_table/favorites/mod.rs | 1 - crates/_types/enums/src/by_table/mod.rs | 2 +- .../enums/src/by_table/user_bookmarks/mod.rs | 1 + .../user_bookmark_entity_type.rs | 128 ++++++++++++++++++ crates/_types/tokens/src/prefixes.rs | 4 +- crates/_types/tokens/src/tokens/mod.rs | 2 +- .../{favorites.rs => user_bookmarks.rs} | 6 +- .../favorites/favorite_entity_token.rs | 48 ------- .../src/queries/favorites/mod.rs | 7 - crates/lib/mysql_queries/src/queries/mod.rs | 2 +- .../create_user_bookmark.rs} | 22 +-- .../delete_user_bookmark.rs} | 16 +-- .../get_user_bookmark.rs} | 56 ++++---- .../list_user_bookmarks.rs} | 44 +++--- .../list_user_bookmarks_for_entity.rs} | 36 ++--- .../list_user_bookmarks_result.rs} | 40 +++--- .../src/queries/user_bookmarks/mod.rs | 7 + .../user_bookmark_entity_token.rs | 48 +++++++ .../list_favorites_for_entity_handler.rs | 122 ----------------- .../http_server/endpoints/favorites/mod.rs | 5 - .../src/http_server/endpoints/mod.rs | 2 +- .../create_user_bookmark_handler.rs} | 62 ++++----- .../delete_user_bookmark_handler.rs} | 52 +++---- .../list_user_bookmarks_for_entity_handler.rs | 122 +++++++++++++++++ ...ist_user_bookmarks_for_session_handler.rs} | 76 +++++------ .../list_user_bookmarks_for_user_handler.rs} | 74 +++++----- .../endpoints/user_bookmarks/mod.rs | 5 + .../service/web/storyteller_web/src/routes.rs | 22 +-- 39 files changed, 661 insertions(+), 608 deletions(-) rename .sqlx/{query-f1ef63978793e7da5bd5e1a486254dd436db8021c8f049efa41f43cf7ce75f1d.json => query-02136088e16742de2154cd9e84eeebbdb76045ad26aeb1c517a54c296bf31087.json} (76%) rename .sqlx/{query-99cff649bf75f5b05330e7db8536ecc832affbae7c9710e158099079609e5e16.json => query-1c1ef2195e81362d0eb023ede236c6fa65ede80d9efcaa4996694ce32c12cc0c.json} (76%) create mode 100644 .sqlx/query-576e5a72e385d44a1e53dc473dd0b5a04e33d7c6b9c38bef96f275b064a12386.json delete mode 100644 .sqlx/query-6a9fc0a3d983eb1d2bdf7d4c80904d73b9f4a649098fc0ba78cbc20cfde12437.json delete mode 100644 .sqlx/query-72eaa9124662acf0ed354b868fcdfe33c94b61046c30940f55cdc73789f94041.json rename .sqlx/{query-4214d8e86b81eb0138a34702ce12960ee007ca602a7bd64b68924515f8fbb038.json => query-d9c00b3c78ed6ec31b281c7ea5fb1efd0cfa6b20899151f9e7f1a122c1f7a70e.json} (70%) create mode 100644 .sqlx/query-e8f3bb68896d316498b52fdaaf4c352624b79bd4e097f57db5ad59f53fd66995.json rename .sqlx/{query-c33f8df5a9ed1991366d6078460d9e936a5470d1794ea319d6cf19b0f5338fd4.json => query-eea9531d5261833b93baadee8b99449362c074fc2397e23ecd175b6a0425b16b.json} (70%) create mode 100644 _sql/migrations/2023-12-11-115710_add user_bookmarks/down.sql create mode 100644 _sql/migrations/2023-12-11-115710_add user_bookmarks/up.sql delete mode 100644 crates/_types/enums/src/by_table/favorites/favorite_entity_type.rs delete mode 100644 crates/_types/enums/src/by_table/favorites/mod.rs create mode 100644 crates/_types/enums/src/by_table/user_bookmarks/mod.rs create mode 100644 crates/_types/enums/src/by_table/user_bookmarks/user_bookmark_entity_type.rs rename crates/_types/tokens/src/tokens/{favorites.rs => user_bookmarks.rs} (59%) delete mode 100644 crates/lib/mysql_queries/src/queries/favorites/favorite_entity_token.rs delete mode 100644 crates/lib/mysql_queries/src/queries/favorites/mod.rs rename crates/lib/mysql_queries/src/queries/{favorites/create_favorite.rs => user_bookmarks/create_user_bookmark.rs} (67%) rename crates/lib/mysql_queries/src/queries/{favorites/delete_favorite.rs => user_bookmarks/delete_user_bookmark.rs} (61%) rename crates/lib/mysql_queries/src/queries/{favorites/get_favorite.rs => user_bookmarks/get_user_bookmark.rs} (51%) rename crates/lib/mysql_queries/src/queries/{favorites/list_user_favorites.rs => user_bookmarks/list_user_bookmarks.rs} (75%) rename crates/lib/mysql_queries/src/queries/{favorites/list_favorites_for_entity.rs => user_bookmarks/list_user_bookmarks_for_entity.rs} (67%) rename crates/lib/mysql_queries/src/queries/{favorites/list_user_favorites_result.rs => user_bookmarks/list_user_bookmarks_result.rs} (66%) create mode 100644 crates/lib/mysql_queries/src/queries/user_bookmarks/mod.rs create mode 100644 crates/lib/mysql_queries/src/queries/user_bookmarks/user_bookmark_entity_token.rs delete mode 100644 crates/service/web/storyteller_web/src/http_server/endpoints/favorites/list_favorites_for_entity_handler.rs delete mode 100644 crates/service/web/storyteller_web/src/http_server/endpoints/favorites/mod.rs rename crates/service/web/storyteller_web/src/http_server/endpoints/{favorites/create_favorite_handler.rs => user_bookmarks/create_user_bookmark_handler.rs} (52%) rename crates/service/web/storyteller_web/src/http_server/endpoints/{favorites/delete_favorite_handler.rs => user_bookmarks/delete_user_bookmark_handler.rs} (58%) create mode 100644 crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/list_user_bookmarks_for_entity_handler.rs rename crates/service/web/storyteller_web/src/http_server/endpoints/{favorites/list_favorites_for_session_handler.rs => user_bookmarks/list_user_bookmarks_for_session_handler.rs} (51%) rename crates/service/web/storyteller_web/src/http_server/endpoints/{favorites/list_favorites_for_user_handler.rs => user_bookmarks/list_user_bookmarks_for_user_handler.rs} (51%) create mode 100644 crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/mod.rs diff --git a/.sqlx/query-f1ef63978793e7da5bd5e1a486254dd436db8021c8f049efa41f43cf7ce75f1d.json b/.sqlx/query-02136088e16742de2154cd9e84eeebbdb76045ad26aeb1c517a54c296bf31087.json similarity index 76% rename from .sqlx/query-f1ef63978793e7da5bd5e1a486254dd436db8021c8f049efa41f43cf7ce75f1d.json rename to .sqlx/query-02136088e16742de2154cd9e84eeebbdb76045ad26aeb1c517a54c296bf31087.json index 0115c0bc84..047b14d7ff 100644 --- a/.sqlx/query-f1ef63978793e7da5bd5e1a486254dd436db8021c8f049efa41f43cf7ce75f1d.json +++ b/.sqlx/query-02136088e16742de2154cd9e84eeebbdb76045ad26aeb1c517a54c296bf31087.json @@ -1,11 +1,11 @@ { "db_name": "MySQL", - "query": "\nSELECT\n f.token as `token: tokens::tokens::favorites::FavoriteToken`,\n\n f.entity_type as `entity_type: enums::by_table::favorites::favorite_entity_type::FavoriteEntityType`,\n f.entity_token,\n\n f.user_token as `user_token: tokens::tokens::users::UserToken`,\n u.username,\n u.display_name as user_display_name,\n u.email_gravatar_hash as user_gravatar_hash,\n\n f.created_at,\n f.updated_at,\n f.deleted_at\n\nFROM\n favorites AS f\nJOIN users AS u\n ON f.user_token = u.token\nWHERE\n f.token = ?\n ", + "query": "\nSELECT\n f.token as `token: tokens::tokens::user_bookmarks::UserBookmarkToken`,\n\n f.entity_type as `entity_type: enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType`,\n f.entity_token,\n\n f.user_token as `user_token: tokens::tokens::users::UserToken`,\n u.username,\n u.display_name as user_display_name,\n u.email_gravatar_hash as user_gravatar_hash,\n\n f.created_at,\n f.updated_at,\n f.deleted_at\n\nFROM\n user_bookmarks AS f\nJOIN users AS u\n ON f.user_token = u.token\nWHERE\n f.token = ?\n ", "describe": { "columns": [ { "ordinal": 0, - "name": "token: tokens::tokens::favorites::FavoriteToken", + "name": "token: tokens::tokens::user_bookmarks::UserBookmarkToken", "type_info": { "type": "VarString", "flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE", @@ -15,7 +15,7 @@ }, { "ordinal": 1, - "name": "entity_type: enums::by_table::favorites::favorite_entity_type::FavoriteEntityType", + "name": "entity_type: enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType", "type_info": { "type": "VarString", "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE", @@ -120,5 +120,5 @@ true ] }, - "hash": "f1ef63978793e7da5bd5e1a486254dd436db8021c8f049efa41f43cf7ce75f1d" + "hash": "02136088e16742de2154cd9e84eeebbdb76045ad26aeb1c517a54c296bf31087" } diff --git a/.sqlx/query-99cff649bf75f5b05330e7db8536ecc832affbae7c9710e158099079609e5e16.json b/.sqlx/query-1c1ef2195e81362d0eb023ede236c6fa65ede80d9efcaa4996694ce32c12cc0c.json similarity index 76% rename from .sqlx/query-99cff649bf75f5b05330e7db8536ecc832affbae7c9710e158099079609e5e16.json rename to .sqlx/query-1c1ef2195e81362d0eb023ede236c6fa65ede80d9efcaa4996694ce32c12cc0c.json index c4b6c41fdb..48546a186c 100644 --- a/.sqlx/query-99cff649bf75f5b05330e7db8536ecc832affbae7c9710e158099079609e5e16.json +++ b/.sqlx/query-1c1ef2195e81362d0eb023ede236c6fa65ede80d9efcaa4996694ce32c12cc0c.json @@ -1,11 +1,11 @@ { "db_name": "MySQL", - "query": "\nSELECT\n f.token as `token: tokens::tokens::favorites::FavoriteToken`,\n f.user_token as `user_token: tokens::tokens::users::UserToken`,\n u.username,\n u.display_name as user_display_name,\n u.email_gravatar_hash as user_gravatar_hash,\n\n f.created_at,\n f.updated_at,\n f.deleted_at\n\nFROM\n favorites AS f\nJOIN users AS u\n ON f.user_token = u.token\nWHERE\n f.entity_type = ?\n AND f.entity_token = ?\n AND f.deleted_at IS NULL\nORDER BY f.id DESC\nLIMIT 50\n ", + "query": "\nSELECT\n f.token as `token: tokens::tokens::user_bookmarks::UserBookmarkToken`,\n f.user_token as `user_token: tokens::tokens::users::UserToken`,\n u.username,\n u.display_name as user_display_name,\n u.email_gravatar_hash as user_gravatar_hash,\n\n f.created_at,\n f.updated_at,\n f.deleted_at\n\nFROM\n user_bookmarks AS f\nJOIN users AS u\n ON f.user_token = u.token\nWHERE\n f.entity_type = ?\n AND f.entity_token = ?\n AND f.deleted_at IS NULL\nORDER BY f.id DESC\nLIMIT 50\n ", "describe": { "columns": [ { "ordinal": 0, - "name": "token: tokens::tokens::favorites::FavoriteToken", + "name": "token: tokens::tokens::user_bookmarks::UserBookmarkToken", "type_info": { "type": "VarString", "flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE", @@ -98,5 +98,5 @@ true ] }, - "hash": "99cff649bf75f5b05330e7db8536ecc832affbae7c9710e158099079609e5e16" + "hash": "1c1ef2195e81362d0eb023ede236c6fa65ede80d9efcaa4996694ce32c12cc0c" } diff --git a/.sqlx/query-576e5a72e385d44a1e53dc473dd0b5a04e33d7c6b9c38bef96f275b064a12386.json b/.sqlx/query-576e5a72e385d44a1e53dc473dd0b5a04e33d7c6b9c38bef96f275b064a12386.json new file mode 100644 index 0000000000..c829a96d4d --- /dev/null +++ b/.sqlx/query-576e5a72e385d44a1e53dc473dd0b5a04e33d7c6b9c38bef96f275b064a12386.json @@ -0,0 +1,12 @@ +{ + "db_name": "MySQL", + "query": "\nUPDATE user_bookmarks\nSET\ndeleted_at = CURRENT_TIMESTAMP,\nversion = version + 1\nWHERE\ntoken = ?\nAND user_token = ?\nLIMIT 1\n ", + "describe": { + "columns": [], + "parameters": { + "Right": 2 + }, + "nullable": [] + }, + "hash": "576e5a72e385d44a1e53dc473dd0b5a04e33d7c6b9c38bef96f275b064a12386" +} diff --git a/.sqlx/query-6a9fc0a3d983eb1d2bdf7d4c80904d73b9f4a649098fc0ba78cbc20cfde12437.json b/.sqlx/query-6a9fc0a3d983eb1d2bdf7d4c80904d73b9f4a649098fc0ba78cbc20cfde12437.json deleted file mode 100644 index fefdbaf494..0000000000 --- a/.sqlx/query-6a9fc0a3d983eb1d2bdf7d4c80904d73b9f4a649098fc0ba78cbc20cfde12437.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "MySQL", - "query": "\nUPDATE favorites\nSET\ndeleted_at = CURRENT_TIMESTAMP,\nversion = version + 1\nWHERE\ntoken = ?\nAND user_token = ?\nLIMIT 1\n ", - "describe": { - "columns": [], - "parameters": { - "Right": 2 - }, - "nullable": [] - }, - "hash": "6a9fc0a3d983eb1d2bdf7d4c80904d73b9f4a649098fc0ba78cbc20cfde12437" -} diff --git a/.sqlx/query-72eaa9124662acf0ed354b868fcdfe33c94b61046c30940f55cdc73789f94041.json b/.sqlx/query-72eaa9124662acf0ed354b868fcdfe33c94b61046c30940f55cdc73789f94041.json deleted file mode 100644 index 01e7177d85..0000000000 --- a/.sqlx/query-72eaa9124662acf0ed354b868fcdfe33c94b61046c30940f55cdc73789f94041.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "MySQL", - "query": "\nINSERT INTO favorites\nSET\n token = ?,\n user_token = ?,\n entity_type = ?,\n entity_token = ?\n\nON DUPLICATE KEY UPDATE\n deleted_at = NULL,\n version = version + 1\n ", - "describe": { - "columns": [], - "parameters": { - "Right": 4 - }, - "nullable": [] - }, - "hash": "72eaa9124662acf0ed354b868fcdfe33c94b61046c30940f55cdc73789f94041" -} diff --git a/.sqlx/query-4214d8e86b81eb0138a34702ce12960ee007ca602a7bd64b68924515f8fbb038.json b/.sqlx/query-d9c00b3c78ed6ec31b281c7ea5fb1efd0cfa6b20899151f9e7f1a122c1f7a70e.json similarity index 70% rename from .sqlx/query-4214d8e86b81eb0138a34702ce12960ee007ca602a7bd64b68924515f8fbb038.json rename to .sqlx/query-d9c00b3c78ed6ec31b281c7ea5fb1efd0cfa6b20899151f9e7f1a122c1f7a70e.json index 2c4133a738..33334d1769 100644 --- a/.sqlx/query-4214d8e86b81eb0138a34702ce12960ee007ca602a7bd64b68924515f8fbb038.json +++ b/.sqlx/query-d9c00b3c78ed6ec31b281c7ea5fb1efd0cfa6b20899151f9e7f1a122c1f7a70e.json @@ -1,11 +1,11 @@ { "db_name": "MySQL", - "query": "\nSELECT\n f.token as `token: tokens::tokens::favorites::FavoriteToken`,\n f.entity_type as `entity_type: enums::by_table::favorites::favorite_entity_type::FavoriteEntityType`,\n f.entity_token,\n f.user_token as `user_token: tokens::tokens::users::UserToken`,\n u.username,\n u.display_name as user_display_name,\n u.email_gravatar_hash as user_gravatar_hash,\n f.created_at,\n f.updated_at,\n f.deleted_at,\n\n media_files.media_type as `maybe_media_file_type: enums::by_table::media_files::media_file_type::MediaFileType`,\n media_files.origin_product_category as `maybe_media_file_origin_category: enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory`,\n\n tts_models.title as maybe_descriptive_text_tts_model_title,\n tts_results.raw_inference_text as maybe_descriptive_text_tts_result_inference_text,\n users.display_name as maybe_descriptive_text_user_display_name,\n voice_conversion_models.title as maybe_descriptive_text_voice_conversion_model_title,\n zs_voices.title as maybe_descriptive_text_zs_voice_title\n\nFROM\n favorites AS f\nJOIN users AS u\n ON f.user_token = u.token\n\nLEFT OUTER JOIN media_files ON media_files.token = f.entity_token\nLEFT OUTER JOIN tts_models ON tts_models.token = f.entity_token\nLEFT OUTER JOIN tts_results ON tts_results.token = f.entity_token\nLEFT OUTER JOIN users ON users.token = f.entity_token\nLEFT OUTER JOIN voice_conversion_models ON voice_conversion_models.token = f.entity_token\nLEFT OUTER JOIN zs_voices ON zs_voices.token = f.entity_token\n\nWHERE\n u.username = ?\n AND f.entity_type = ?\n AND f.deleted_at IS NULL\nORDER BY f.id DESC\nLIMIT 50\n ", + "query": "\nSELECT\n f.token as `token: tokens::tokens::user_bookmarks::UserBookmarkToken`,\n f.entity_type as `entity_type: enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType`,\n f.entity_token,\n f.user_token as `user_token: tokens::tokens::users::UserToken`,\n u.username,\n u.display_name as user_display_name,\n u.email_gravatar_hash as user_gravatar_hash,\n f.created_at,\n f.updated_at,\n f.deleted_at,\n\n media_files.media_type as `maybe_media_file_type: enums::by_table::media_files::media_file_type::MediaFileType`,\n media_files.origin_product_category as `maybe_media_file_origin_category: enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory`,\n\n tts_models.title as maybe_descriptive_text_tts_model_title,\n tts_results.raw_inference_text as maybe_descriptive_text_tts_result_inference_text,\n users.display_name as maybe_descriptive_text_user_display_name,\n voice_conversion_models.title as maybe_descriptive_text_voice_conversion_model_title,\n zs_voices.title as maybe_descriptive_text_zs_voice_title\n\nFROM\n user_bookmarks AS f\nJOIN users AS u\n ON f.user_token = u.token\n\nLEFT OUTER JOIN media_files ON media_files.token = f.entity_token\nLEFT OUTER JOIN tts_models ON tts_models.token = f.entity_token\nLEFT OUTER JOIN tts_results ON tts_results.token = f.entity_token\nLEFT OUTER JOIN users ON users.token = f.entity_token\nLEFT OUTER JOIN voice_conversion_models ON voice_conversion_models.token = f.entity_token\nLEFT OUTER JOIN zs_voices ON zs_voices.token = f.entity_token\n\nWHERE\n u.username = ?\n AND f.entity_type = ?\n AND f.deleted_at IS NULL\nORDER BY f.id DESC\nLIMIT 50\n ", "describe": { "columns": [ { "ordinal": 0, - "name": "token: tokens::tokens::favorites::FavoriteToken", + "name": "token: tokens::tokens::user_bookmarks::UserBookmarkToken", "type_info": { "type": "VarString", "flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE", @@ -15,7 +15,7 @@ }, { "ordinal": 1, - "name": "entity_type: enums::by_table::favorites::favorite_entity_type::FavoriteEntityType", + "name": "entity_type: enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType", "type_info": { "type": "VarString", "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE", @@ -197,5 +197,5 @@ true ] }, - "hash": "4214d8e86b81eb0138a34702ce12960ee007ca602a7bd64b68924515f8fbb038" + "hash": "d9c00b3c78ed6ec31b281c7ea5fb1efd0cfa6b20899151f9e7f1a122c1f7a70e" } diff --git a/.sqlx/query-e8f3bb68896d316498b52fdaaf4c352624b79bd4e097f57db5ad59f53fd66995.json b/.sqlx/query-e8f3bb68896d316498b52fdaaf4c352624b79bd4e097f57db5ad59f53fd66995.json new file mode 100644 index 0000000000..d2dc52c79e --- /dev/null +++ b/.sqlx/query-e8f3bb68896d316498b52fdaaf4c352624b79bd4e097f57db5ad59f53fd66995.json @@ -0,0 +1,12 @@ +{ + "db_name": "MySQL", + "query": "\nINSERT INTO user_bookmarks\nSET\n token = ?,\n user_token = ?,\n entity_type = ?,\n entity_token = ?\n\nON DUPLICATE KEY UPDATE\n deleted_at = NULL,\n version = version + 1\n ", + "describe": { + "columns": [], + "parameters": { + "Right": 4 + }, + "nullable": [] + }, + "hash": "e8f3bb68896d316498b52fdaaf4c352624b79bd4e097f57db5ad59f53fd66995" +} diff --git a/.sqlx/query-c33f8df5a9ed1991366d6078460d9e936a5470d1794ea319d6cf19b0f5338fd4.json b/.sqlx/query-eea9531d5261833b93baadee8b99449362c074fc2397e23ecd175b6a0425b16b.json similarity index 70% rename from .sqlx/query-c33f8df5a9ed1991366d6078460d9e936a5470d1794ea319d6cf19b0f5338fd4.json rename to .sqlx/query-eea9531d5261833b93baadee8b99449362c074fc2397e23ecd175b6a0425b16b.json index 4ebd7fa022..55d497beee 100644 --- a/.sqlx/query-c33f8df5a9ed1991366d6078460d9e936a5470d1794ea319d6cf19b0f5338fd4.json +++ b/.sqlx/query-eea9531d5261833b93baadee8b99449362c074fc2397e23ecd175b6a0425b16b.json @@ -1,11 +1,11 @@ { "db_name": "MySQL", - "query": "\nSELECT\n f.token as `token: tokens::tokens::favorites::FavoriteToken`,\n f.entity_type as `entity_type: enums::by_table::favorites::favorite_entity_type::FavoriteEntityType`,\n f.entity_token,\n f.user_token as `user_token: tokens::tokens::users::UserToken`,\n u.username,\n u.display_name as user_display_name,\n u.email_gravatar_hash as user_gravatar_hash,\n f.created_at,\n f.updated_at,\n f.deleted_at,\n\n media_files.media_type as `maybe_media_file_type: enums::by_table::media_files::media_file_type::MediaFileType`,\n media_files.origin_product_category as `maybe_media_file_origin_category: enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory`,\n\n tts_models.title as maybe_descriptive_text_tts_model_title,\n tts_results.raw_inference_text as maybe_descriptive_text_tts_result_inference_text,\n users.display_name as maybe_descriptive_text_user_display_name,\n voice_conversion_models.title as maybe_descriptive_text_voice_conversion_model_title,\n zs_voices.title as maybe_descriptive_text_zs_voice_title\n\nFROM\n favorites AS f\nJOIN users AS u\n ON f.user_token = u.token\n\nLEFT OUTER JOIN media_files ON media_files.token = f.entity_token\nLEFT OUTER JOIN tts_models ON tts_models.token = f.entity_token\nLEFT OUTER JOIN tts_results ON tts_results.token = f.entity_token\nLEFT OUTER JOIN users ON users.token = f.entity_token\nLEFT OUTER JOIN voice_conversion_models ON voice_conversion_models.token = f.entity_token\nLEFT OUTER JOIN zs_voices ON zs_voices.token = f.entity_token\n\nWHERE\n u.username = ?\n AND f.deleted_at IS NULL\nORDER BY f.id DESC\nLIMIT 50\n ", + "query": "\nSELECT\n f.token as `token: tokens::tokens::user_bookmarks::UserBookmarkToken`,\n f.entity_type as `entity_type: enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType`,\n f.entity_token,\n f.user_token as `user_token: tokens::tokens::users::UserToken`,\n u.username,\n u.display_name as user_display_name,\n u.email_gravatar_hash as user_gravatar_hash,\n f.created_at,\n f.updated_at,\n f.deleted_at,\n\n media_files.media_type as `maybe_media_file_type: enums::by_table::media_files::media_file_type::MediaFileType`,\n media_files.origin_product_category as `maybe_media_file_origin_category: enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory`,\n\n tts_models.title as maybe_descriptive_text_tts_model_title,\n tts_results.raw_inference_text as maybe_descriptive_text_tts_result_inference_text,\n users.display_name as maybe_descriptive_text_user_display_name,\n voice_conversion_models.title as maybe_descriptive_text_voice_conversion_model_title,\n zs_voices.title as maybe_descriptive_text_zs_voice_title\n\nFROM\n user_bookmarks AS f\nJOIN users AS u\n ON f.user_token = u.token\n\nLEFT OUTER JOIN media_files ON media_files.token = f.entity_token\nLEFT OUTER JOIN tts_models ON tts_models.token = f.entity_token\nLEFT OUTER JOIN tts_results ON tts_results.token = f.entity_token\nLEFT OUTER JOIN users ON users.token = f.entity_token\nLEFT OUTER JOIN voice_conversion_models ON voice_conversion_models.token = f.entity_token\nLEFT OUTER JOIN zs_voices ON zs_voices.token = f.entity_token\n\nWHERE\n u.username = ?\n AND f.deleted_at IS NULL\nORDER BY f.id DESC\nLIMIT 50\n ", "describe": { "columns": [ { "ordinal": 0, - "name": "token: tokens::tokens::favorites::FavoriteToken", + "name": "token: tokens::tokens::user_bookmarks::UserBookmarkToken", "type_info": { "type": "VarString", "flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE", @@ -15,7 +15,7 @@ }, { "ordinal": 1, - "name": "entity_type: enums::by_table::favorites::favorite_entity_type::FavoriteEntityType", + "name": "entity_type: enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType", "type_info": { "type": "VarString", "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE", @@ -197,5 +197,5 @@ true ] }, - "hash": "c33f8df5a9ed1991366d6078460d9e936a5470d1794ea319d6cf19b0f5338fd4" + "hash": "eea9531d5261833b93baadee8b99449362c074fc2397e23ecd175b6a0425b16b" } diff --git a/_sql/migrations/2023-12-11-115710_add user_bookmarks/down.sql b/_sql/migrations/2023-12-11-115710_add user_bookmarks/down.sql new file mode 100644 index 0000000000..8b6d041461 --- /dev/null +++ b/_sql/migrations/2023-12-11-115710_add user_bookmarks/down.sql @@ -0,0 +1,5 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +DROP TABLE user_bookmarks; \ No newline at end of file diff --git a/_sql/migrations/2023-12-11-115710_add user_bookmarks/up.sql b/_sql/migrations/2023-12-11-115710_add user_bookmarks/up.sql new file mode 100644 index 0000000000..54ad3a50b0 --- /dev/null +++ b/_sql/migrations/2023-12-11-115710_add user_bookmarks/up.sql @@ -0,0 +1,46 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +-- Favorites that can be attached to just about anything. +-- This is a polymorphic table and can apply to a wide variety of entities. +CREATE TABLE user_bookmarks +( + -- Not used for anything except replication. + id BIGINT(20) NOT NULL AUTO_INCREMENT, + + -- Effective "primary key" (PUBLIC) + token VARCHAR(32) NOT NULL, + + -- User making the favorite + user_token VARCHAR(32) NOT NULL, + + -- The type of entity the favorite applies to + entity_type VARCHAR(32) NOT NULL, + + -- The token of the entity the favorite applies to + entity_token VARCHAR(32) NOT NULL, + + -- ========== VECTOR CLOCK ========== + + -- Incremented with every update. + version INT NOT NULL DEFAULT 0, + + -- ========== TIMESTAMPS ========== + + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + deleted_at TIMESTAMP NULL, + + -- INDICES -- + PRIMARY KEY (id), + UNIQUE KEY (token), + KEY index_entity_type_entity_token (entity_type, entity_token), + KEY index_user_token_entity_token (user_token, entity_type), + KEY index_user_token (user_token), + KEY index_created_at (created_at), + KEY index_user_deleted_at (deleted_at) + +) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE = utf8mb4_bin; diff --git a/crates/_types/enums/src/by_table/favorites/favorite_entity_type.rs b/crates/_types/enums/src/by_table/favorites/favorite_entity_type.rs deleted file mode 100644 index 5b96603ff1..0000000000 --- a/crates/_types/enums/src/by_table/favorites/favorite_entity_type.rs +++ /dev/null @@ -1,128 +0,0 @@ -use serde::Deserialize; -use serde::Serialize; -#[cfg(test)] -use strum::EnumCount; -#[cfg(test)] -use strum::EnumIter; - -/// Used in the `favorites` table in a `VARCHAR(32)` field named `entity_type`. -#[cfg_attr(test, derive(EnumIter, EnumCount))] -#[derive(Clone, Copy, Eq, PartialEq, Hash, Deserialize, Serialize)] -pub enum FavoriteEntityType { - /// User - #[serde(rename = "user")] - User, - - /// TTS model (architecture does not matter) - #[serde(rename = "tts_model")] - TtsModel, - - /// TTS result (architecture does not matter) - #[serde(rename = "tts_result")] - TtsResult, - - /// W2L template - #[serde(rename = "w2l_template")] - W2lTemplate, - - /// W2L result - #[serde(rename = "w2l_result")] - W2lResult, - - /// MediaFile - #[serde(rename = "media_file")] - MediaFile, - - /// VoiceConversionModel - #[serde(rename = "voice_conversion_model")] - VoiceConversionModel, - - /// ZsVoice - #[serde(rename = "zs_voice")] - ZsVoice, -} - -// TODO(bt, 2023-01-17): This desperately needs MySQL integration tests! -impl_enum_display_and_debug_using_to_str!(FavoriteEntityType); -impl_mysql_enum_coders!(FavoriteEntityType); - -/// NB: Legacy API for older code. -impl FavoriteEntityType { - pub fn to_str(&self) -> &'static str { - match self { - Self::User => "user", - Self::TtsModel => "tts_model", - Self::TtsResult => "tts_result", - Self::W2lTemplate => "w2l_template", - Self::W2lResult => "w2l_result", - Self::MediaFile => "media_file", - Self::VoiceConversionModel => "voice_conversion_model", - Self::ZsVoice => "zs_voice", - } - } - - pub fn from_str(value: &str) -> Result { - match value { - "user" => Ok(Self::User), - "tts_model" => Ok(Self::TtsModel), - "tts_result" => Ok(Self::TtsResult), - "w2l_template" => Ok(Self::W2lTemplate), - "w2l_result" => Ok(Self::W2lResult), - "media_file" => Ok(Self::MediaFile), - "voice_conversion_model" => Ok(Self::VoiceConversionModel), - "zs_voice" => Ok(Self::ZsVoice), - _ => Err(format!("invalid value: {:?}", value)), - } - } -} - -#[cfg(test)] -mod tests { - use crate::by_table::favorites::favorite_entity_type::FavoriteEntityType; - use crate::test_helpers::assert_serialization; - - mod serde { - use super::*; - - #[test] - fn test_serialization() { - assert_serialization(FavoriteEntityType::User, "user"); - assert_serialization(FavoriteEntityType::TtsModel, "tts_model"); - assert_serialization(FavoriteEntityType::TtsResult, "tts_result"); - assert_serialization(FavoriteEntityType::W2lTemplate, "w2l_template"); - assert_serialization(FavoriteEntityType::W2lResult, "w2l_result"); - assert_serialization(FavoriteEntityType::MediaFile, "media_file"); - assert_serialization(FavoriteEntityType::VoiceConversionModel, "voice_conversion_model"); - assert_serialization(FavoriteEntityType::ZsVoice, "zs_voice"); - } - } - - mod impl_methods { - use super::*; - - #[test] - fn test_to_str() { - assert_eq!(FavoriteEntityType::User.to_str(), "user"); - assert_eq!(FavoriteEntityType::TtsModel.to_str(), "tts_model"); - assert_eq!(FavoriteEntityType::TtsResult.to_str(), "tts_result"); - assert_eq!(FavoriteEntityType::W2lTemplate.to_str(), "w2l_template"); - assert_eq!(FavoriteEntityType::W2lResult.to_str(), "w2l_result"); - assert_eq!(FavoriteEntityType::MediaFile.to_str(), "media_file"); - assert_eq!(FavoriteEntityType::VoiceConversionModel.to_str(), "voice_conversion_model"); - assert_eq!(FavoriteEntityType::ZsVoice.to_str(), "zs_voice"); - } - - #[test] - fn test_from_str() { - assert_eq!(FavoriteEntityType::from_str("user").unwrap(), FavoriteEntityType::User); - assert_eq!(FavoriteEntityType::from_str("tts_model").unwrap(), FavoriteEntityType::TtsModel); - assert_eq!(FavoriteEntityType::from_str("tts_result").unwrap(), FavoriteEntityType::TtsResult); - assert_eq!(FavoriteEntityType::from_str("w2l_template").unwrap(), FavoriteEntityType::W2lTemplate); - assert_eq!(FavoriteEntityType::from_str("w2l_result").unwrap(), FavoriteEntityType::W2lResult); - assert_eq!(FavoriteEntityType::from_str("media_file").unwrap(), FavoriteEntityType::MediaFile); - assert_eq!(FavoriteEntityType::from_str("voice_conversion_model").unwrap(), FavoriteEntityType::VoiceConversionModel); - assert_eq!(FavoriteEntityType::from_str("zs_voice").unwrap(), FavoriteEntityType::ZsVoice); - assert!(FavoriteEntityType::from_str("foo").is_err()); - } - } -} diff --git a/crates/_types/enums/src/by_table/favorites/mod.rs b/crates/_types/enums/src/by_table/favorites/mod.rs deleted file mode 100644 index 18ac93ed9c..0000000000 --- a/crates/_types/enums/src/by_table/favorites/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod favorite_entity_type; \ No newline at end of file diff --git a/crates/_types/enums/src/by_table/mod.rs b/crates/_types/enums/src/by_table/mod.rs index 91f8cb15da..97876b2094 100644 --- a/crates/_types/enums/src/by_table/mod.rs +++ b/crates/_types/enums/src/by_table/mod.rs @@ -10,6 +10,7 @@ pub mod media_uploads; pub mod model_categories; pub mod trending_model_analytics; pub mod tts_models; +pub mod user_bookmarks; pub mod user_ratings; pub mod voice_conversion_models; pub mod voice_conversion_results; @@ -19,4 +20,3 @@ pub mod model_weights; pub mod tts_render_tasks; pub mod web_rendition_targets; pub mod web_scraping_targets; -pub mod favorites; diff --git a/crates/_types/enums/src/by_table/user_bookmarks/mod.rs b/crates/_types/enums/src/by_table/user_bookmarks/mod.rs new file mode 100644 index 0000000000..c3c539aad3 --- /dev/null +++ b/crates/_types/enums/src/by_table/user_bookmarks/mod.rs @@ -0,0 +1 @@ +pub mod user_bookmark_entity_type; \ No newline at end of file diff --git a/crates/_types/enums/src/by_table/user_bookmarks/user_bookmark_entity_type.rs b/crates/_types/enums/src/by_table/user_bookmarks/user_bookmark_entity_type.rs new file mode 100644 index 0000000000..69bf47cf5e --- /dev/null +++ b/crates/_types/enums/src/by_table/user_bookmarks/user_bookmark_entity_type.rs @@ -0,0 +1,128 @@ +use serde::Deserialize; +use serde::Serialize; +#[cfg(test)] +use strum::EnumCount; +#[cfg(test)] +use strum::EnumIter; + +/// Used in the `user_bookmarks` table in a `VARCHAR(32)` field named `entity_type`. +#[cfg_attr(test, derive(EnumIter, EnumCount))] +#[derive(Clone, Copy, Eq, PartialEq, Hash, Deserialize, Serialize)] +pub enum UserBookmarkEntityType { + /// User + #[serde(rename = "user")] + User, + + /// TTS model (architecture does not matter) + #[serde(rename = "tts_model")] + TtsModel, + + /// TTS result (architecture does not matter) + #[serde(rename = "tts_result")] + TtsResult, + + /// W2L template + #[serde(rename = "w2l_template")] + W2lTemplate, + + /// W2L result + #[serde(rename = "w2l_result")] + W2lResult, + + /// MediaFile + #[serde(rename = "media_file")] + MediaFile, + + /// VoiceConversionModel + #[serde(rename = "voice_conversion_model")] + VoiceConversionModel, + + /// ZsVoice + #[serde(rename = "zs_voice")] + ZsVoice, +} + +// TODO(bt, 2023-01-17): This desperately needs MySQL integration tests! +impl_enum_display_and_debug_using_to_str!(UserBookmarkEntityType); +impl_mysql_enum_coders!(UserBookmarkEntityType); + +/// NB: Legacy API for older code. +impl UserBookmarkEntityType { + pub fn to_str(&self) -> &'static str { + match self { + Self::User => "user", + Self::TtsModel => "tts_model", + Self::TtsResult => "tts_result", + Self::W2lTemplate => "w2l_template", + Self::W2lResult => "w2l_result", + Self::MediaFile => "media_file", + Self::VoiceConversionModel => "voice_conversion_model", + Self::ZsVoice => "zs_voice", + } + } + + pub fn from_str(value: &str) -> Result { + match value { + "user" => Ok(Self::User), + "tts_model" => Ok(Self::TtsModel), + "tts_result" => Ok(Self::TtsResult), + "w2l_template" => Ok(Self::W2lTemplate), + "w2l_result" => Ok(Self::W2lResult), + "media_file" => Ok(Self::MediaFile), + "voice_conversion_model" => Ok(Self::VoiceConversionModel), + "zs_voice" => Ok(Self::ZsVoice), + _ => Err(format!("invalid value: {:?}", value)), + } + } +} + +#[cfg(test)] +mod tests { + use crate::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType; + use crate::test_helpers::assert_serialization; + + mod serde { + use super::*; + + #[test] + fn test_serialization() { + assert_serialization(UserBookmarkEntityType::User, "user"); + assert_serialization(UserBookmarkEntityType::TtsModel, "tts_model"); + assert_serialization(UserBookmarkEntityType::TtsResult, "tts_result"); + assert_serialization(UserBookmarkEntityType::W2lTemplate, "w2l_template"); + assert_serialization(UserBookmarkEntityType::W2lResult, "w2l_result"); + assert_serialization(UserBookmarkEntityType::MediaFile, "media_file"); + assert_serialization(UserBookmarkEntityType::VoiceConversionModel, "voice_conversion_model"); + assert_serialization(UserBookmarkEntityType::ZsVoice, "zs_voice"); + } + } + + mod impl_methods { + use super::*; + + #[test] + fn test_to_str() { + assert_eq!(UserBookmarkEntityType::User.to_str(), "user"); + assert_eq!(UserBookmarkEntityType::TtsModel.to_str(), "tts_model"); + assert_eq!(UserBookmarkEntityType::TtsResult.to_str(), "tts_result"); + assert_eq!(UserBookmarkEntityType::W2lTemplate.to_str(), "w2l_template"); + assert_eq!(UserBookmarkEntityType::W2lResult.to_str(), "w2l_result"); + assert_eq!(UserBookmarkEntityType::MediaFile.to_str(), "media_file"); + assert_eq!(UserBookmarkEntityType::VoiceConversionModel.to_str(), "voice_conversion_model"); + assert_eq!(UserBookmarkEntityType::ZsVoice.to_str(), "zs_voice"); + } + + #[test] + fn test_from_str() { + assert_eq!(UserBookmarkEntityType::from_str("user").unwrap(), UserBookmarkEntityType::User); + assert_eq!(UserBookmarkEntityType::from_str("tts_model").unwrap(), UserBookmarkEntityType::TtsModel); + assert_eq!(UserBookmarkEntityType::from_str("tts_result").unwrap(), UserBookmarkEntityType::TtsResult); + assert_eq!(UserBookmarkEntityType::from_str("w2l_template").unwrap(), UserBookmarkEntityType::W2lTemplate); + assert_eq!(UserBookmarkEntityType::from_str("w2l_result").unwrap(), UserBookmarkEntityType::W2lResult); + assert_eq!(UserBookmarkEntityType::from_str("media_file").unwrap(), UserBookmarkEntityType::MediaFile); + assert_eq!(UserBookmarkEntityType::from_str("voice_conversion_model").unwrap(), UserBookmarkEntityType::VoiceConversionModel); + assert_eq!(UserBookmarkEntityType::from_str("zs_voice").unwrap(), UserBookmarkEntityType::ZsVoice); + assert!(UserBookmarkEntityType::from_str("foo").is_err()); + } + } +} diff --git a/crates/_types/tokens/src/prefixes.rs b/crates/_types/tokens/src/prefixes.rs index 6e24a9802b..382492bae4 100644 --- a/crates/_types/tokens/src/prefixes.rs +++ b/crates/_types/tokens/src/prefixes.rs @@ -27,7 +27,6 @@ pub(crate) enum TokenPrefix { Comment, DownloadJob, EmailSenderJob, - Favorite, InferenceJob, MediaFile, MediaUpload, @@ -36,6 +35,7 @@ pub(crate) enum TokenPrefix { PasswordReset, TtsRenderTask, // NB: aichatbot / sqlite User, + UserBookmark, UserSession, VoiceConversionModel, VoiceConversionResult, @@ -94,7 +94,6 @@ impl PrefixGenerator for TokenPrefix { Self::DownloadJob => "jdown_", // NB: Previously "JGUP:" Self::EmailSenderJob => "email_job_", Self::InferenceJob => "jinf_", - Self::Favorite => "fav_", Self::MediaFile => "m_", Self::MediaUpload => "mu_", Self::ModelWeight => "weight_", @@ -102,6 +101,7 @@ impl PrefixGenerator for TokenPrefix { Self::PasswordReset => "pw_reset_", Self::TtsRenderTask => "tts_task_", Self::User => "user_", // NB: Previously "U:" + Self::UserBookmark => "ub_", Self::UserSession => "session_", Self::VoiceConversionModel => "vcm_", Self::VoiceConversionResult => "vcr_", diff --git a/crates/_types/tokens/src/tokens/mod.rs b/crates/_types/tokens/src/tokens/mod.rs index e75f732b55..b7c4eed592 100644 --- a/crates/_types/tokens/src/tokens/mod.rs +++ b/crates/_types/tokens/src/tokens/mod.rs @@ -34,4 +34,4 @@ pub mod w2l_templates; pub mod zs_voice_dataset_samples; pub mod zs_voice_datasets; pub mod zs_voices; -pub mod favorites; +pub mod user_bookmarks; diff --git a/crates/_types/tokens/src/tokens/favorites.rs b/crates/_types/tokens/src/tokens/user_bookmarks.rs similarity index 59% rename from crates/_types/tokens/src/tokens/favorites.rs rename to crates/_types/tokens/src/tokens/user_bookmarks.rs index 78ecb7e0b9..ac91dc079d 100644 --- a/crates/_types/tokens/src/tokens/favorites.rs +++ b/crates/_types/tokens/src/tokens/user_bookmarks.rs @@ -8,7 +8,7 @@ use crate::prefixes::TokenPrefix; /// The primary key for Audit Logs. #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, sqlx::Type, Debug, Serialize, Deserialize)] #[sqlx(transparent)] -pub struct FavoriteToken(pub String); +pub struct UserBookmarkToken(pub String); -impl_string_token!(FavoriteToken); -impl_crockford_generator!(FavoriteToken, 32usize, TokenPrefix::Favorite, CrockfordLower); +impl_string_token!(UserBookmarkToken); +impl_crockford_generator!(UserBookmarkToken, 32usize, TokenPrefix::UserBookmark, CrockfordLower); diff --git a/crates/lib/mysql_queries/src/queries/favorites/favorite_entity_token.rs b/crates/lib/mysql_queries/src/queries/favorites/favorite_entity_token.rs deleted file mode 100644 index 3a0007253f..0000000000 --- a/crates/lib/mysql_queries/src/queries/favorites/favorite_entity_token.rs +++ /dev/null @@ -1,48 +0,0 @@ -use enums::by_table::favorites::favorite_entity_type::FavoriteEntityType; -use tokens::tokens::media_files::MediaFileToken; -use tokens::tokens::tts_models::TtsModelToken; -use tokens::tokens::tts_results::TtsResultToken; -use tokens::tokens::users::UserToken; -use tokens::tokens::voice_conversion_models::VoiceConversionModelToken; -use tokens::tokens::w2l_results::W2lResultToken; -use tokens::tokens::w2l_templates::W2lTemplateToken; -use tokens::tokens::zs_voices::ZsVoiceToken; - -pub enum FavoriteEntityToken { - User(UserToken), - TtsModel(TtsModelToken), - TtsResult(TtsResultToken), - W2lTemplate(W2lTemplateToken), - W2lResult(W2lResultToken), - MediaFile(MediaFileToken), - VoiceConversionModel(VoiceConversionModelToken), - ZsVoice(ZsVoiceToken), -} - -impl FavoriteEntityToken { - pub fn from_entity_type_and_token(entity_type: FavoriteEntityType, token: &str) -> Self { - match entity_type { - FavoriteEntityType::User => Self::User(UserToken::new_from_str(token)), - FavoriteEntityType::TtsModel => Self::TtsModel(TtsModelToken::new_from_str(token)), - FavoriteEntityType::TtsResult => Self::TtsResult(TtsResultToken::new_from_str(token)), - FavoriteEntityType::W2lTemplate => Self::W2lTemplate(W2lTemplateToken::new_from_str(token)), - FavoriteEntityType::W2lResult => Self::W2lResult(W2lResultToken::new_from_str(token)), - FavoriteEntityType::MediaFile => Self::MediaFile(MediaFileToken::new_from_str(token)), - FavoriteEntityType::VoiceConversionModel => Self::VoiceConversionModel(VoiceConversionModelToken::new_from_str(token)), - FavoriteEntityType::ZsVoice => Self::ZsVoice(ZsVoiceToken::new_from_str(token)), - } - } - - pub fn get_composite_keys(&self) -> (FavoriteEntityType, &str) { - match self { - FavoriteEntityToken::User(user_token) => (FavoriteEntityType::User, user_token.as_str()), - FavoriteEntityToken::TtsModel(tts_model_token) => (FavoriteEntityType::TtsModel, tts_model_token.as_str()), - FavoriteEntityToken::TtsResult(tts_result_token) => (FavoriteEntityType::TtsResult, tts_result_token.as_str()), - FavoriteEntityToken::W2lTemplate(w2l_template_token) => (FavoriteEntityType::W2lTemplate, w2l_template_token.as_str()), - FavoriteEntityToken::W2lResult(w2l_result_token) => (FavoriteEntityType::W2lResult, w2l_result_token.as_str()), - FavoriteEntityToken::MediaFile(media_file_token) => (FavoriteEntityType::MediaFile, media_file_token.as_str()), - FavoriteEntityToken::VoiceConversionModel(voice_conversion_model_token) => (FavoriteEntityType::VoiceConversionModel, voice_conversion_model_token.as_str()), - FavoriteEntityToken::ZsVoice(zs_voice_token) => (FavoriteEntityType::ZsVoice, zs_voice_token.as_str()), - } - } -} diff --git a/crates/lib/mysql_queries/src/queries/favorites/mod.rs b/crates/lib/mysql_queries/src/queries/favorites/mod.rs deleted file mode 100644 index 8cc8a3c7c5..0000000000 --- a/crates/lib/mysql_queries/src/queries/favorites/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub mod create_favorite; -pub mod delete_favorite; -pub mod favorite_entity_token; -pub mod get_favorite; -pub mod list_favorites_for_entity; -pub mod list_user_favorites; -pub mod list_user_favorites_result; \ No newline at end of file diff --git a/crates/lib/mysql_queries/src/queries/mod.rs b/crates/lib/mysql_queries/src/queries/mod.rs index 1acd2d7a89..39499425b4 100644 --- a/crates/lib/mysql_queries/src/queries/mod.rs +++ b/crates/lib/mysql_queries/src/queries/mod.rs @@ -3,7 +3,6 @@ pub mod audit_logs; pub mod billing; pub mod comments; pub mod email_sender_jobs; -pub mod favorites; pub mod generic_download; pub mod generic_inference; pub mod generic_synthetic_ids; @@ -18,6 +17,7 @@ pub mod trending_model_analytics; pub mod tts; pub mod twitch; pub mod users; +pub mod user_bookmarks; pub mod vocoder; pub mod voice_clone_requests; pub mod voice_conversion; diff --git a/crates/lib/mysql_queries/src/queries/favorites/create_favorite.rs b/crates/lib/mysql_queries/src/queries/user_bookmarks/create_user_bookmark.rs similarity index 67% rename from crates/lib/mysql_queries/src/queries/favorites/create_favorite.rs rename to crates/lib/mysql_queries/src/queries/user_bookmarks/create_user_bookmark.rs index a6decf5fff..b897d8daaf 100644 --- a/crates/lib/mysql_queries/src/queries/favorites/create_favorite.rs +++ b/crates/lib/mysql_queries/src/queries/user_bookmarks/create_user_bookmark.rs @@ -4,15 +4,15 @@ use anyhow::anyhow; use sqlx::{Executor, MySql}; use errors::AnyhowResult; -use tokens::tokens::favorites::FavoriteToken; +use tokens::tokens::user_bookmarks::UserBookmarkToken; use tokens::tokens::users::UserToken; -use crate::queries::favorites::favorite_entity_token::FavoriteEntityToken; +use crate::queries::user_bookmarks::user_bookmark_entity_token::UserBookmarkEntityToken; -pub struct CreateFavoriteArgs<'e, 'c, E> +pub struct CreateUserBookmarkArgs<'e, 'c, E> where E: 'e + Executor<'c, Database = MySql> { - pub entity_token: &'e FavoriteEntityToken, + pub entity_token: &'e UserBookmarkEntityToken, pub user_token: &'e UserToken, @@ -23,19 +23,19 @@ pub struct CreateFavoriteArgs<'e, 'c, E> pub phantom: PhantomData<&'c E>, } -pub async fn create_favorite<'e, 'c : 'e, E>( - args: CreateFavoriteArgs<'e, 'c, E>, +pub async fn create_user_bookmark<'e, 'c : 'e, E>( + args: CreateUserBookmarkArgs<'e, 'c, E>, ) - -> AnyhowResult + -> AnyhowResult where E: 'e + Executor<'c, Database = MySql> { - let favorite_token = FavoriteToken::generate(); + let user_bookmark_token = UserBookmarkToken::generate(); let (entity_type, entity_token) = args.entity_token.get_composite_keys(); let query_result = sqlx::query!( r#" -INSERT INTO favorites +INSERT INTO user_bookmarks SET token = ?, user_token = ?, @@ -46,7 +46,7 @@ ON DUPLICATE KEY UPDATE deleted_at = NULL, version = version + 1 "#, - &favorite_token, + &user_bookmark_token, args.user_token, entity_type, entity_token, @@ -59,5 +59,5 @@ ON DUPLICATE KEY UPDATE Err(err) => return Err(anyhow!("Mysql error: {:?}", err)), }; - Ok(favorite_token) + Ok(user_bookmark_token) } diff --git a/crates/lib/mysql_queries/src/queries/favorites/delete_favorite.rs b/crates/lib/mysql_queries/src/queries/user_bookmarks/delete_user_bookmark.rs similarity index 61% rename from crates/lib/mysql_queries/src/queries/favorites/delete_favorite.rs rename to crates/lib/mysql_queries/src/queries/user_bookmarks/delete_user_bookmark.rs index 0ec20c4e6a..025b6f51c7 100644 --- a/crates/lib/mysql_queries/src/queries/favorites/delete_favorite.rs +++ b/crates/lib/mysql_queries/src/queries/user_bookmarks/delete_user_bookmark.rs @@ -1,22 +1,22 @@ use sqlx::{Executor, MySql}; use errors::AnyhowResult; -use tokens::tokens::favorites::FavoriteToken; +use tokens::tokens::user_bookmarks::UserBookmarkToken; use tokens::tokens::users::UserToken; // NB: UserToken is only supplied as an optimistic form of validation -pub async fn delete_favorite<'e, 'c, E>( - favorite_token: &'e FavoriteToken, - user_token: &'e UserToken, - mysql_executor: E +pub async fn delete_user_bookmark<'e, 'c, E>( + user_bookmark_token: &'e UserBookmarkToken, + user_token: &'e UserToken, + mysql_executor: E ) - -> AnyhowResult<()> + -> AnyhowResult<()> where E: 'e + Executor<'c, Database = MySql> { sqlx::query!( r#" -UPDATE favorites +UPDATE user_bookmarks SET deleted_at = CURRENT_TIMESTAMP, version = version + 1 @@ -25,7 +25,7 @@ token = ? AND user_token = ? LIMIT 1 "#, - favorite_token, + user_bookmark_token, user_token ) .execute(mysql_executor) diff --git a/crates/lib/mysql_queries/src/queries/favorites/get_favorite.rs b/crates/lib/mysql_queries/src/queries/user_bookmarks/get_user_bookmark.rs similarity index 51% rename from crates/lib/mysql_queries/src/queries/favorites/get_favorite.rs rename to crates/lib/mysql_queries/src/queries/user_bookmarks/get_user_bookmark.rs index 01d46404bc..efb6903070 100644 --- a/crates/lib/mysql_queries/src/queries/favorites/get_favorite.rs +++ b/crates/lib/mysql_queries/src/queries/user_bookmarks/get_user_bookmark.rs @@ -2,15 +2,15 @@ use anyhow::anyhow; use chrono::{DateTime, Utc}; use sqlx::{Executor, MySql}; -use enums::by_table::favorites::favorite_entity_type::FavoriteEntityType; +use enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType; use errors::AnyhowResult; -use tokens::tokens::favorites::FavoriteToken; +use tokens::tokens::user_bookmarks::UserBookmarkToken; use tokens::tokens::users::UserToken; -pub struct Favorite { - pub token: FavoriteToken, +pub struct UserBookmark { + pub token: UserBookmarkToken, - pub entity_type: FavoriteEntityType, + pub entity_type: UserBookmarkEntityType, pub entity_token: String, pub user_token: UserToken, @@ -23,21 +23,21 @@ pub struct Favorite { pub maybe_deleted_at: Option>, } -pub async fn get_favorite<'e, 'c, E>( - favorite_token: &'e FavoriteToken, - mysql_executor: E +pub async fn get_user_bookmark<'e, 'c, E>( + user_bookmark_token: &'e UserBookmarkToken, + mysql_executor: E ) - -> AnyhowResult> + -> AnyhowResult> where E: 'e + Executor<'c, Database = MySql> { let maybe_results = sqlx::query_as!( - RawFavorite, + RawUserBookmark, r#" SELECT - f.token as `token: tokens::tokens::favorites::FavoriteToken`, + f.token as `token: tokens::tokens::user_bookmarks::UserBookmarkToken`, - f.entity_type as `entity_type: enums::by_table::favorites::favorite_entity_type::FavoriteEntityType`, + f.entity_type as `entity_type: enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType`, f.entity_token, f.user_token as `user_token: tokens::tokens::users::UserToken`, @@ -50,29 +50,29 @@ SELECT f.deleted_at FROM - favorites AS f + user_bookmarks AS f JOIN users AS u ON f.user_token = u.token WHERE f.token = ? "#, - favorite_token + user_bookmark_token ) .fetch_one(mysql_executor) .await; match maybe_results { - Ok(favorite) => Ok(Some(Favorite { - token: favorite.token, - entity_type: favorite.entity_type, - entity_token: favorite.entity_token, - user_token: favorite.user_token, - username: favorite.username, - user_display_name: favorite.user_display_name, - user_gravatar_hash: favorite.user_gravatar_hash, - created_at: favorite.created_at, - updated_at: favorite.updated_at, - maybe_deleted_at: favorite.deleted_at, + Ok(user_bookmark) => Ok(Some(UserBookmark { + token: user_bookmark.token, + entity_type: user_bookmark.entity_type, + entity_token: user_bookmark.entity_token, + user_token: user_bookmark.user_token, + username: user_bookmark.username, + user_display_name: user_bookmark.user_display_name, + user_gravatar_hash: user_bookmark.user_gravatar_hash, + created_at: user_bookmark.created_at, + updated_at: user_bookmark.updated_at, + maybe_deleted_at: user_bookmark.deleted_at, })), Err(err) => match err { sqlx::Error::RowNotFound => Ok(None), @@ -81,10 +81,10 @@ WHERE } } -pub struct RawFavorite { - pub token: FavoriteToken, +pub struct RawUserBookmark { + pub token: UserBookmarkToken, - pub entity_type: FavoriteEntityType, + pub entity_type: UserBookmarkEntityType, pub entity_token: String, pub user_token: UserToken, diff --git a/crates/lib/mysql_queries/src/queries/favorites/list_user_favorites.rs b/crates/lib/mysql_queries/src/queries/user_bookmarks/list_user_bookmarks.rs similarity index 75% rename from crates/lib/mysql_queries/src/queries/favorites/list_user_favorites.rs rename to crates/lib/mysql_queries/src/queries/user_bookmarks/list_user_bookmarks.rs index f42c7da477..1e1896a750 100644 --- a/crates/lib/mysql_queries/src/queries/favorites/list_user_favorites.rs +++ b/crates/lib/mysql_queries/src/queries/user_bookmarks/list_user_bookmarks.rs @@ -2,24 +2,26 @@ use anyhow::anyhow; use log::warn; use sqlx::MySqlPool; -use enums::by_table::favorites::favorite_entity_type::FavoriteEntityType; +use enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType; use errors::AnyhowResult; +use crate::queries::user_bookmarks::list_user_bookmarks_result::UserBookmark; +use crate::queries::user_bookmarks::list_user_bookmarks_result::RawUserBookmarkRecord; +use tokens::tokens::user_bookmarks::UserBookmarkToken; -use crate::queries::favorites::list_user_favorites_result::{RawUserFavoriteRecord, UserFavorite}; -pub async fn list_user_favorites( +pub async fn list_user_bookmarks( username: &str, mysql_pool: &MySqlPool -) -> AnyhowResult> { +) -> AnyhowResult> { /// TODO(bt,2023-11-21): Maybe this query can use a switch /// See: https://stackoverflow.com/questions/2761574/mysql-use-case-else-value-as-join-parameter let maybe_results= sqlx::query_as!( - RawUserFavoriteRecord, + RawUserBookmarkRecord, r#" SELECT - f.token as `token: tokens::tokens::favorites::FavoriteToken`, - f.entity_type as `entity_type: enums::by_table::favorites::favorite_entity_type::FavoriteEntityType`, + f.token as `token: tokens::tokens::user_bookmarks::UserBookmarkToken`, + f.entity_type as `entity_type: enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType`, f.entity_token, f.user_token as `user_token: tokens::tokens::users::UserToken`, u.username, @@ -39,7 +41,7 @@ SELECT zs_voices.title as maybe_descriptive_text_zs_voice_title FROM - favorites AS f + user_bookmarks AS f JOIN users AS u ON f.user_token = u.token @@ -65,28 +67,28 @@ LIMIT 50 Err(err) => match err { sqlx::Error::RowNotFound => Ok(Vec::new()), _ => { - warn!("list favorites db error: {:?}", err); + warn!("list user_bookmarks db error: {:?}", err); Err(anyhow!("error with query: {:?}", err)) } }, Ok(results) => Ok(results.into_iter() - .map(|favorite| favorite.into_public_type()) + .map(|user_bookmark| user_bookmark.into_public_type()) .collect()), } } -pub async fn list_user_favorites_by_entity_type( - username: &str, - entity_type: FavoriteEntityType, - mysql_pool: &MySqlPool -) -> AnyhowResult> { +pub async fn list_user_user_bookmarks_by_entity_type( + username: &str, + entity_type: UserBookmarkEntityType, + mysql_pool: &MySqlPool +) -> AnyhowResult> { let maybe_results= sqlx::query_as!( - RawUserFavoriteRecord, + RawUserBookmarkRecord, r#" SELECT - f.token as `token: tokens::tokens::favorites::FavoriteToken`, - f.entity_type as `entity_type: enums::by_table::favorites::favorite_entity_type::FavoriteEntityType`, + f.token as `token: tokens::tokens::user_bookmarks::UserBookmarkToken`, + f.entity_type as `entity_type: enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType`, f.entity_token, f.user_token as `user_token: tokens::tokens::users::UserToken`, u.username, @@ -106,7 +108,7 @@ SELECT zs_voices.title as maybe_descriptive_text_zs_voice_title FROM - favorites AS f + user_bookmarks AS f JOIN users AS u ON f.user_token = u.token @@ -134,12 +136,12 @@ LIMIT 50 Err(err) => match err { sqlx::Error::RowNotFound => Ok(Vec::new()), _ => { - warn!("list favorites db error: {:?}", err); + warn!("list user_bookmarks db error: {:?}", err); Err(anyhow!("error with query: {:?}", err)) } }, Ok(results) => Ok(results.into_iter() - .map(|favorite| favorite.into_public_type()) + .map(|user_bookmark| user_bookmark.into_public_type()) .collect()), } } diff --git a/crates/lib/mysql_queries/src/queries/favorites/list_favorites_for_entity.rs b/crates/lib/mysql_queries/src/queries/user_bookmarks/list_user_bookmarks_for_entity.rs similarity index 67% rename from crates/lib/mysql_queries/src/queries/favorites/list_favorites_for_entity.rs rename to crates/lib/mysql_queries/src/queries/user_bookmarks/list_user_bookmarks_for_entity.rs index e1080ac694..3df0f0812c 100644 --- a/crates/lib/mysql_queries/src/queries/favorites/list_favorites_for_entity.rs +++ b/crates/lib/mysql_queries/src/queries/user_bookmarks/list_user_bookmarks_for_entity.rs @@ -4,13 +4,13 @@ use log::warn; use sqlx::MySqlPool; use errors::AnyhowResult; -use tokens::tokens::favorites::FavoriteToken; +use tokens::tokens::user_bookmarks::UserBookmarkToken; use tokens::tokens::users::UserToken; -use crate::queries::favorites::favorite_entity_token::FavoriteEntityToken; +use crate::queries::user_bookmarks::user_bookmark_entity_token::UserBookmarkEntityToken; -pub struct Favorite { - pub token: FavoriteToken, +pub struct UserBookmark { + pub token: UserBookmarkToken, pub user_token: UserToken, pub username: String, @@ -22,18 +22,18 @@ pub struct Favorite { pub maybe_deleted_at: Option>, } -pub async fn list_favorites_for_entity( - favorite_entity_token: FavoriteEntityToken, +pub async fn list_user_bookmarks_for_entity( + user_bookmark_entity_token: UserBookmarkEntityToken, mysql_pool: &MySqlPool -) -> AnyhowResult> { +) -> AnyhowResult> { - let (entity_type, entity_token) = favorite_entity_token.get_composite_keys(); + let (entity_type, entity_token) = user_bookmark_entity_token.get_composite_keys(); let maybe_results= sqlx::query_as!( - RawFavoriteRecord, + RawUserBookmarkRecord, r#" SELECT - f.token as `token: tokens::tokens::favorites::FavoriteToken`, + f.token as `token: tokens::tokens::user_bookmarks::UserBookmarkToken`, f.user_token as `user_token: tokens::tokens::users::UserToken`, u.username, u.display_name as user_display_name, @@ -44,7 +44,7 @@ SELECT f.deleted_at FROM - favorites AS f + user_bookmarks AS f JOIN users AS u ON f.user_token = u.token WHERE @@ -64,18 +64,18 @@ LIMIT 50 Err(err) => match err { sqlx::Error::RowNotFound => Ok(Vec::new()), _ => { - warn!("list favorites db error: {:?}", err); + warn!("list user_bookmarks db error: {:?}", err); Err(anyhow!("error with query: {:?}", err)) } }, Ok(results) => Ok(results.into_iter() - .map(|favorite| favorite.into_public_type()) + .map(|user_bookmark| user_bookmark.into_public_type()) .collect()), } } -pub struct RawFavoriteRecord { - token: FavoriteToken, +pub struct RawUserBookmarkRecord { + token: UserBookmarkToken, user_token: UserToken, username: String, @@ -87,9 +87,9 @@ pub struct RawFavoriteRecord { deleted_at: Option>, } -impl RawFavoriteRecord { - pub fn into_public_type(self) -> Favorite { - Favorite { +impl RawUserBookmarkRecord { + pub fn into_public_type(self) -> UserBookmark { + UserBookmark { token: self.token, user_token: self.user_token, username: self.username, diff --git a/crates/lib/mysql_queries/src/queries/favorites/list_user_favorites_result.rs b/crates/lib/mysql_queries/src/queries/user_bookmarks/list_user_bookmarks_result.rs similarity index 66% rename from crates/lib/mysql_queries/src/queries/favorites/list_user_favorites_result.rs rename to crates/lib/mysql_queries/src/queries/user_bookmarks/list_user_bookmarks_result.rs index c391a5d8e6..e56d1de9d8 100644 --- a/crates/lib/mysql_queries/src/queries/favorites/list_user_favorites_result.rs +++ b/crates/lib/mysql_queries/src/queries/user_bookmarks/list_user_bookmarks_result.rs @@ -1,18 +1,18 @@ use chrono::{DateTime, Utc}; -use enums::by_table::favorites::favorite_entity_type::FavoriteEntityType; +use enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType; use enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory; use enums::by_table::media_files::media_file_type::MediaFileType; -use tokens::tokens::favorites::FavoriteToken; +use tokens::tokens::user_bookmarks::UserBookmarkToken; use tokens::tokens::users::UserToken; -pub struct UserFavorite { - pub token: FavoriteToken, +pub struct UserBookmark { + pub token: UserBookmarkToken, - pub entity_type: FavoriteEntityType, + pub entity_type: UserBookmarkEntityType, pub entity_token: String, - /// Something descriptive about the favorited entity. + /// Something descriptive about the bookmarked entity. /// This might be TTS text, a username, etc. It depends on the entity type. pub maybe_entity_descriptive_text: Option, @@ -26,10 +26,10 @@ pub struct UserFavorite { pub maybe_deleted_at: Option>, } -pub struct RawUserFavoriteRecord { - pub (crate) token: FavoriteToken, +pub struct RawUserBookmarkRecord { + pub (crate) token: UserBookmarkToken, - pub (crate) entity_type: FavoriteEntityType, + pub (crate) entity_type: UserBookmarkEntityType, pub (crate) entity_token: String, pub (crate) user_token: UserToken, @@ -51,27 +51,27 @@ pub struct RawUserFavoriteRecord { pub (crate) maybe_descriptive_text_zs_voice_title: Option, } -impl RawUserFavoriteRecord { - pub fn into_public_type(self) -> UserFavorite { - UserFavorite { +impl RawUserBookmarkRecord { + pub fn into_public_type(self) -> UserBookmark { + UserBookmark { token: self.token, entity_type: self.entity_type, entity_token: self.entity_token, maybe_entity_descriptive_text: match self.entity_type { - FavoriteEntityType::User => self.maybe_descriptive_text_user_display_name, - FavoriteEntityType::TtsModel => self.maybe_descriptive_text_tts_model_title, - FavoriteEntityType::TtsResult => self.maybe_descriptive_text_tts_result_inference_text, - FavoriteEntityType::W2lTemplate => None, - FavoriteEntityType::W2lResult => None, + UserBookmarkEntityType::User => self.maybe_descriptive_text_user_display_name, + UserBookmarkEntityType::TtsModel => self.maybe_descriptive_text_tts_model_title, + UserBookmarkEntityType::TtsResult => self.maybe_descriptive_text_tts_result_inference_text, + UserBookmarkEntityType::W2lTemplate => None, + UserBookmarkEntityType::W2lResult => None, // TODO(bt,2023-11-21): Summary text needs to be better enriched. - FavoriteEntityType::MediaFile => self.maybe_media_file_type + UserBookmarkEntityType::MediaFile => self.maybe_media_file_type .and_then(|media_file_type| match media_file_type { MediaFileType::Audio => Some("audio media file".to_string()), MediaFileType::Image => Some("image media file".to_string()), MediaFileType::Video => Some("video media file".to_string()), }), - FavoriteEntityType::VoiceConversionModel => self.maybe_descriptive_text_voice_conversion_model_title, - FavoriteEntityType::ZsVoice => self.maybe_descriptive_text_zs_voice_title, + UserBookmarkEntityType::VoiceConversionModel => self.maybe_descriptive_text_voice_conversion_model_title, + UserBookmarkEntityType::ZsVoice => self.maybe_descriptive_text_zs_voice_title, }, user_token: self.user_token, username: self.username, diff --git a/crates/lib/mysql_queries/src/queries/user_bookmarks/mod.rs b/crates/lib/mysql_queries/src/queries/user_bookmarks/mod.rs new file mode 100644 index 0000000000..df6d7f415c --- /dev/null +++ b/crates/lib/mysql_queries/src/queries/user_bookmarks/mod.rs @@ -0,0 +1,7 @@ +pub mod delete_user_bookmark; +pub mod create_user_bookmark; +pub mod user_bookmark_entity_token; +pub mod get_user_bookmark; +pub mod list_user_bookmarks_for_entity; +pub mod list_user_bookmarks; +pub mod list_user_bookmarks_result; \ No newline at end of file diff --git a/crates/lib/mysql_queries/src/queries/user_bookmarks/user_bookmark_entity_token.rs b/crates/lib/mysql_queries/src/queries/user_bookmarks/user_bookmark_entity_token.rs new file mode 100644 index 0000000000..5fbf8224ad --- /dev/null +++ b/crates/lib/mysql_queries/src/queries/user_bookmarks/user_bookmark_entity_token.rs @@ -0,0 +1,48 @@ +use enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType; +use tokens::tokens::media_files::MediaFileToken; +use tokens::tokens::tts_models::TtsModelToken; +use tokens::tokens::tts_results::TtsResultToken; +use tokens::tokens::users::UserToken; +use tokens::tokens::voice_conversion_models::VoiceConversionModelToken; +use tokens::tokens::w2l_results::W2lResultToken; +use tokens::tokens::w2l_templates::W2lTemplateToken; +use tokens::tokens::zs_voices::ZsVoiceToken; + +pub enum UserBookmarkEntityToken { + User(UserToken), + TtsModel(TtsModelToken), + TtsResult(TtsResultToken), + W2lTemplate(W2lTemplateToken), + W2lResult(W2lResultToken), + MediaFile(MediaFileToken), + VoiceConversionModel(VoiceConversionModelToken), + ZsVoice(ZsVoiceToken), +} + +impl UserBookmarkEntityToken { + pub fn from_entity_type_and_token(entity_type: UserBookmarkEntityType, token: &str) -> Self { + match entity_type { + UserBookmarkEntityType::User => Self::User(UserToken::new_from_str(token)), + UserBookmarkEntityType::TtsModel => Self::TtsModel(TtsModelToken::new_from_str(token)), + UserBookmarkEntityType::TtsResult => Self::TtsResult(TtsResultToken::new_from_str(token)), + UserBookmarkEntityType::W2lTemplate => Self::W2lTemplate(W2lTemplateToken::new_from_str(token)), + UserBookmarkEntityType::W2lResult => Self::W2lResult(W2lResultToken::new_from_str(token)), + UserBookmarkEntityType::MediaFile => Self::MediaFile(MediaFileToken::new_from_str(token)), + UserBookmarkEntityType::VoiceConversionModel => Self::VoiceConversionModel(VoiceConversionModelToken::new_from_str(token)), + UserBookmarkEntityType::ZsVoice => Self::ZsVoice(ZsVoiceToken::new_from_str(token)), + } + } + + pub fn get_composite_keys(&self) -> (UserBookmarkEntityType, &str) { + match self { + UserBookmarkEntityToken::User(user_token) => (UserBookmarkEntityType::User, user_token.as_str()), + UserBookmarkEntityToken::TtsModel(tts_model_token) => (UserBookmarkEntityType::TtsModel, tts_model_token.as_str()), + UserBookmarkEntityToken::TtsResult(tts_result_token) => (UserBookmarkEntityType::TtsResult, tts_result_token.as_str()), + UserBookmarkEntityToken::W2lTemplate(w2l_template_token) => (UserBookmarkEntityType::W2lTemplate, w2l_template_token.as_str()), + UserBookmarkEntityToken::W2lResult(w2l_result_token) => (UserBookmarkEntityType::W2lResult, w2l_result_token.as_str()), + UserBookmarkEntityToken::MediaFile(media_file_token) => (UserBookmarkEntityType::MediaFile, media_file_token.as_str()), + UserBookmarkEntityToken::VoiceConversionModel(voice_conversion_model_token) => (UserBookmarkEntityType::VoiceConversionModel, voice_conversion_model_token.as_str()), + UserBookmarkEntityToken::ZsVoice(zs_voice_token) => (UserBookmarkEntityType::ZsVoice, zs_voice_token.as_str()), + } + } +} diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/favorites/list_favorites_for_entity_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/favorites/list_favorites_for_entity_handler.rs deleted file mode 100644 index efbb773b84..0000000000 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/favorites/list_favorites_for_entity_handler.rs +++ /dev/null @@ -1,122 +0,0 @@ -// NB: Incrementally getting rid of build warnings... -#![forbid(unused_imports)] -#![forbid(unused_mut)] -#![forbid(unused_variables)] - -use std::fmt; -use std::sync::Arc; - -use actix_web::{HttpRequest, HttpResponse, web}; -use actix_web::error::ResponseError; -use actix_web::http::StatusCode; -use actix_web::web::Path; -use chrono::{DateTime, Utc}; -use log::warn; - -use enums::by_table::favorites::favorite_entity_type::FavoriteEntityType; -use mysql_queries::queries::favorites::favorite_entity_token::FavoriteEntityToken; -use mysql_queries::queries::favorites::list_favorites_for_entity::list_favorites_for_entity; -use tokens::tokens::favorites::FavoriteToken; - -use crate::http_server::common_responses::user_details_lite::{DefaultAvatarInfo, UserDetailsLight}; -use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; -use crate::server_state::ServerState; - -/// For the URL PathInfo -#[derive(Deserialize)] -pub struct ListFavoritesPathInfo { - entity_type: FavoriteEntityType, - entity_token: String, -} - -#[derive(Serialize)] -pub struct ListFavoritesSuccessResponse { - pub success: bool, - pub favorites: Vec, -} - -#[derive(Serialize)] -pub struct Favorite { - pub token: FavoriteToken, - - pub user: UserDetailsLight, - - pub created_at: DateTime, - pub updated_at: DateTime, -} - -#[derive(Debug)] -pub enum ListFavoritesError { - ServerError, -} - -impl ResponseError for ListFavoritesError { - fn status_code(&self) -> StatusCode { - match *self { - ListFavoritesError::ServerError=> StatusCode::INTERNAL_SERVER_ERROR, - } - } - - fn error_response(&self) -> HttpResponse { - let error_reason = match self { - ListFavoritesError::ServerError => "server error".to_string(), - }; - - to_simple_json_error(&error_reason, self.status_code()) - } -} - -// NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for ListFavoritesError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{:?}", self) - } -} - -pub async fn list_favorites_for_entity_handler( - _http_request: HttpRequest, - path: Path, - server_state: web::Data> -) -> Result -{ - let entity_token = FavoriteEntityToken::from_entity_type_and_token( - path.entity_type, &path.entity_token); - - let query_results = list_favorites_for_entity( - entity_token, - &server_state.mysql_pool, - ).await; - - let favorites = match query_results { - Ok(results) => results, - Err(e) => { - warn!("Query error: {:?}", e); - return Err(ListFavoritesError::ServerError); - } - }; - - let response = ListFavoritesSuccessResponse { - success: true, - favorites: favorites.into_iter() - .map(|favorite| Favorite { - token: favorite.token, - user: UserDetailsLight { - user_token: favorite.user_token.clone(), - username: favorite.username.to_string(), // NB: Cloned because of ref use for avatar below - display_name: favorite.user_display_name.clone(), - gravatar_hash: favorite.user_gravatar_hash.clone(), - default_avatar: DefaultAvatarInfo::from_username(&favorite.username), - }, - created_at: favorite.created_at, - updated_at: favorite.updated_at, - }) - .collect(), - }; - - let body = serde_json::to_string(&response) - .map_err(|_e| ListFavoritesError::ServerError)?; - - Ok(HttpResponse::Ok() - .content_type("application/json") - .body(body)) -} diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/favorites/mod.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/favorites/mod.rs deleted file mode 100644 index 4529d2f18b..0000000000 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/favorites/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -pub mod create_favorite_handler; -pub mod delete_favorite_handler; -pub mod list_favorites_for_entity_handler; -pub mod list_favorites_for_session_handler; -pub mod list_favorites_for_user_handler; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/mod.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/mod.rs index d4c32ebd1d..0a6ed9375d 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/mod.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/mod.rs @@ -25,5 +25,5 @@ pub mod voice_clone_requests; pub mod voice_conversion; pub mod voice_designer; pub mod w2l; -pub mod favorites; +pub mod user_bookmarks; pub mod weights; \ No newline at end of file diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/favorites/create_favorite_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/create_user_bookmark_handler.rs similarity index 52% rename from crates/service/web/storyteller_web/src/http_server/endpoints/favorites/create_favorite_handler.rs rename to crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/create_user_bookmark_handler.rs index cb4aa5f5f4..b62fe2feeb 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/favorites/create_favorite_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/create_user_bookmark_handler.rs @@ -11,46 +11,46 @@ use actix_web::error::ResponseError; use actix_web::http::StatusCode; use log::warn; -use enums::by_table::favorites::favorite_entity_type::FavoriteEntityType; -use mysql_queries::queries::favorites::favorite_entity_token::FavoriteEntityToken; -use mysql_queries::queries::favorites::create_favorite::{create_favorite, CreateFavoriteArgs}; -use tokens::tokens::favorites::FavoriteToken; +use enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType; +use mysql_queries::queries::user_bookmarks::user_bookmark_entity_token::UserBookmarkEntityToken; +use mysql_queries::queries::user_bookmarks::create_user_bookmark::{create_user_bookmark, CreateUserBookmarkArgs}; +use tokens::tokens::user_bookmarks::UserBookmarkToken; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; use crate::server_state::ServerState; #[derive(Deserialize)] -pub struct CreateFavoriteRequest { +pub struct CreateUserBookmarkRequest { entity_token: String, - entity_type: FavoriteEntityType, + entity_type: UserBookmarkEntityType, } #[derive(Serialize)] -pub struct CreateFavoriteSuccessResponse { +pub struct CreateUserBookmarkSuccessResponse { pub success: bool, - pub favorite_token: FavoriteToken, + pub user_bookmark_token: UserBookmarkToken, } #[derive(Debug)] -pub enum CreateFavoriteError { +pub enum CreateUserBookmarkError { BadInput(String), NotAuthorized, ServerError, } -impl ResponseError for CreateFavoriteError { +impl ResponseError for CreateUserBookmarkError { fn status_code(&self) -> StatusCode { match *self { - CreateFavoriteError::BadInput(_) => StatusCode::BAD_REQUEST, - CreateFavoriteError::NotAuthorized => StatusCode::UNAUTHORIZED, - CreateFavoriteError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, + CreateUserBookmarkError::BadInput(_) => StatusCode::BAD_REQUEST, + CreateUserBookmarkError::NotAuthorized => StatusCode::UNAUTHORIZED, + CreateUserBookmarkError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, } } fn error_response(&self) -> HttpResponse { let error_reason = match self { - CreateFavoriteError::BadInput(reason) => reason.to_string(), - CreateFavoriteError::NotAuthorized => "unauthorized".to_string(), - CreateFavoriteError::ServerError => "server error".to_string(), + CreateUserBookmarkError::BadInput(reason) => reason.to_string(), + CreateUserBookmarkError::NotAuthorized => "unauthorized".to_string(), + CreateUserBookmarkError::ServerError => "server error".to_string(), }; to_simple_json_error(&error_reason, self.status_code()) @@ -58,24 +58,24 @@ impl ResponseError for CreateFavoriteError { } // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for CreateFavoriteError { +impl fmt::Display for CreateUserBookmarkError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:?}", self) } } -pub async fn create_favorite_handler( +pub async fn create_user_bookmark_handler( http_request: HttpRequest, - request: web::Json, + request: web::Json, server_state: web::Data>, -) -> Result +) -> Result { let mut mysql_connection = server_state.mysql_pool .acquire() .await .map_err(|err| { warn!("MySql pool error: {:?}", err); - CreateFavoriteError::ServerError + CreateUserBookmarkError::ServerError })?; let maybe_user_session = server_state @@ -84,42 +84,42 @@ pub async fn create_favorite_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - CreateFavoriteError::ServerError + CreateUserBookmarkError::ServerError })?; let user_session = match maybe_user_session { Some(session) => session, None => { warn!("not logged in"); - return Err(CreateFavoriteError::NotAuthorized); + return Err(CreateUserBookmarkError::NotAuthorized); } }; - let entity_token = FavoriteEntityToken::from_entity_type_and_token( + let entity_token = UserBookmarkEntityToken::from_entity_type_and_token( request.entity_type, &request.entity_token); - let query_result = create_favorite(CreateFavoriteArgs { + let query_result = create_user_bookmark(CreateUserBookmarkArgs { entity_token: &entity_token, user_token: &user_session.user_token_typed, mysql_executor: &mut *mysql_connection, phantom: Default::default(), }).await; - let favorite_token = match query_result { + let user_bookmark_token = match query_result { Ok(token) => token, Err(err) => { - warn!("error inserting favorite: {:?}", err); - return Err(CreateFavoriteError::ServerError); + warn!("error inserting user_bookmark: {:?}", err); + return Err(CreateUserBookmarkError::ServerError); } }; - let response = CreateFavoriteSuccessResponse { + let response = CreateUserBookmarkSuccessResponse { success: true, - favorite_token, + user_bookmark_token, }; let body = serde_json::to_string(&response) - .map_err(|_e| CreateFavoriteError::ServerError)?; + .map_err(|_e| CreateUserBookmarkError::ServerError)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/favorites/delete_favorite_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/delete_user_bookmark_handler.rs similarity index 58% rename from crates/service/web/storyteller_web/src/http_server/endpoints/favorites/delete_favorite_handler.rs rename to crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/delete_user_bookmark_handler.rs index be28d24534..d68fc29e75 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/favorites/delete_favorite_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/delete_user_bookmark_handler.rs @@ -12,8 +12,8 @@ use actix_web::http::StatusCode; use actix_web::web::Path; use log::warn; -use mysql_queries::queries::favorites::delete_favorite::delete_favorite; -use tokens::tokens::favorites::FavoriteToken; +use mysql_queries::queries::user_bookmarks::delete_user_bookmark::delete_user_bookmark; +use tokens::tokens::user_bookmarks::UserBookmarkToken; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; use crate::http_server::web_utils::response_success_helpers::simple_json_success; @@ -21,40 +21,40 @@ use crate::server_state::ServerState; /// For the URL PathInfo #[derive(Deserialize)] -pub struct DeleteFavoritePathInfo { - favorite_token: FavoriteToken, +pub struct DeleteUserBookmarkPathInfo { + user_bookmark_token: UserBookmarkToken, } #[derive(Deserialize)] -pub struct DeleteFavoriteRequest { +pub struct DeleteUserBookmarkRequest { /// NB: this is only to disambiguate when a user is both a mod and an author. as_mod: Option, } #[derive(Debug)] -pub enum DeleteFavoriteError { +pub enum DeleteUserBookmarkError { BadInput(String), NotAuthorized, NotFound, ServerError, } -impl ResponseError for DeleteFavoriteError { +impl ResponseError for DeleteUserBookmarkError { fn status_code(&self) -> StatusCode { match *self { - DeleteFavoriteError::BadInput(_) => StatusCode::BAD_REQUEST, - DeleteFavoriteError::NotAuthorized => StatusCode::UNAUTHORIZED, - DeleteFavoriteError::NotFound => StatusCode::NOT_FOUND, - DeleteFavoriteError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, + DeleteUserBookmarkError::BadInput(_) => StatusCode::BAD_REQUEST, + DeleteUserBookmarkError::NotAuthorized => StatusCode::UNAUTHORIZED, + DeleteUserBookmarkError::NotFound => StatusCode::NOT_FOUND, + DeleteUserBookmarkError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, } } fn error_response(&self) -> HttpResponse { let error_reason = match self { - DeleteFavoriteError::BadInput(reason) => reason.to_string(), - DeleteFavoriteError::NotAuthorized => "unauthorized".to_string(), - DeleteFavoriteError::NotFound => "not found".to_string(), - DeleteFavoriteError::ServerError => "server error".to_string(), + DeleteUserBookmarkError::BadInput(reason) => reason.to_string(), + DeleteUserBookmarkError::NotAuthorized => "unauthorized".to_string(), + DeleteUserBookmarkError::NotFound => "not found".to_string(), + DeleteUserBookmarkError::ServerError => "server error".to_string(), }; to_simple_json_error(&error_reason, self.status_code()) @@ -62,24 +62,24 @@ impl ResponseError for DeleteFavoriteError { } // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for DeleteFavoriteError { +impl fmt::Display for DeleteUserBookmarkError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:?}", self) } } -pub async fn delete_favorite_handler( +pub async fn delete_user_bookmark_handler( http_request: HttpRequest, - path: Path, - _request: web::Json, + path: Path, + _request: web::Json, server_state: web::Data> -) -> Result { +) -> Result { let mut mysql_connection = server_state.mysql_pool .acquire() .await .map_err(|err| { warn!("MySql pool error: {:?}", err); - DeleteFavoriteError::ServerError + DeleteUserBookmarkError::ServerError })?; let maybe_user_session = server_state @@ -88,18 +88,18 @@ pub async fn delete_favorite_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - DeleteFavoriteError::ServerError + DeleteUserBookmarkError::ServerError })?; let user_session = match maybe_user_session { Some(session) => session, None => { - return Err(DeleteFavoriteError::NotAuthorized); + return Err(DeleteUserBookmarkError::NotAuthorized); } }; - let query_result = delete_favorite( - &path.favorite_token, + let query_result = delete_user_bookmark( + &path.user_bookmark_token, &user_session.user_token_typed, &mut *mysql_connection ).await; @@ -108,7 +108,7 @@ pub async fn delete_favorite_handler( Ok(_) => {}, Err(err) => { warn!("Update tts mod approval status DB error: {:?}", err); - return Err(DeleteFavoriteError::ServerError); + return Err(DeleteUserBookmarkError::ServerError); } }; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/list_user_bookmarks_for_entity_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/list_user_bookmarks_for_entity_handler.rs new file mode 100644 index 0000000000..0fa28887fd --- /dev/null +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/list_user_bookmarks_for_entity_handler.rs @@ -0,0 +1,122 @@ +// NB: Incrementally getting rid of build warnings... +#![forbid(unused_imports)] +#![forbid(unused_mut)] +#![forbid(unused_variables)] + +use std::fmt; +use std::sync::Arc; + +use actix_web::{HttpRequest, HttpResponse, web}; +use actix_web::error::ResponseError; +use actix_web::http::StatusCode; +use actix_web::web::Path; +use chrono::{DateTime, Utc}; +use log::warn; + +use enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType; +use mysql_queries::queries::user_bookmarks::user_bookmark_entity_token::UserBookmarkEntityToken; +use mysql_queries::queries::user_bookmarks::list_user_bookmarks_for_entity::list_user_bookmarks_for_entity; +use tokens::tokens::user_bookmarks::UserBookmarkToken; + +use crate::http_server::common_responses::user_details_lite::{DefaultAvatarInfo, UserDetailsLight}; +use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; +use crate::server_state::ServerState; + +/// For the URL PathInfo +#[derive(Deserialize)] +pub struct ListUserBookmarkPathInfo { + entity_type: UserBookmarkEntityType, + entity_token: String, +} + +#[derive(Serialize)] +pub struct ListUserBookmarksSuccessResponse { + pub success: bool, + pub user_bookmarks: Vec, +} + +#[derive(Serialize)] +pub struct UserBookmark { + pub token: UserBookmarkToken, + + pub user: UserDetailsLight, + + pub created_at: DateTime, + pub updated_at: DateTime, +} + +#[derive(Debug)] +pub enum ListUserBookmarksError { + ServerError, +} + +impl ResponseError for ListUserBookmarksError { + fn status_code(&self) -> StatusCode { + match *self { + ListUserBookmarksError::ServerError=> StatusCode::INTERNAL_SERVER_ERROR, + } + } + + fn error_response(&self) -> HttpResponse { + let error_reason = match self { + ListUserBookmarksError::ServerError => "server error".to_string(), + }; + + to_simple_json_error(&error_reason, self.status_code()) + } +} + +// NB: Not using derive_more::Display since Clion doesn't understand it. +impl fmt::Display for ListUserBookmarksError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", self) + } +} + +pub async fn list_user_bookmarks_for_entity_handler( + _http_request: HttpRequest, + path: Path, + server_state: web::Data> +) -> Result +{ + let entity_token = UserBookmarkEntityToken::from_entity_type_and_token( + path.entity_type, &path.entity_token); + + let query_results = list_user_bookmarks_for_entity( + entity_token, + &server_state.mysql_pool, + ).await; + + let user_bookmarks = match query_results { + Ok(results) => results, + Err(e) => { + warn!("Query error: {:?}", e); + return Err(ListUserBookmarksError::ServerError); + } + }; + + let response = ListUserBookmarksSuccessResponse { + success: true, + user_bookmarks: user_bookmarks.into_iter() + .map(|user_bookmark| UserBookmark { + token: user_bookmark.token, + user: UserDetailsLight { + user_token: user_bookmark.user_token.clone(), + username: user_bookmark.username.to_string(), // NB: Cloned because of ref use for avatar below + display_name: user_bookmark.user_display_name.clone(), + gravatar_hash: user_bookmark.user_gravatar_hash.clone(), + default_avatar: DefaultAvatarInfo::from_username(&user_bookmark.username), + }, + created_at: user_bookmark.created_at, + updated_at: user_bookmark.updated_at, + }) + .collect(), + }; + + let body = serde_json::to_string(&response) + .map_err(|_e| ListUserBookmarksError::ServerError)?; + + Ok(HttpResponse::Ok() + .content_type("application/json") + .body(body)) +} diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/favorites/list_favorites_for_session_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/list_user_bookmarks_for_session_handler.rs similarity index 51% rename from crates/service/web/storyteller_web/src/http_server/endpoints/favorites/list_favorites_for_session_handler.rs rename to crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/list_user_bookmarks_for_session_handler.rs index cdc11f8550..dc1f17d90c 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/favorites/list_favorites_for_session_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/list_user_bookmarks_for_session_handler.rs @@ -13,38 +13,38 @@ use actix_web::web::Query; use chrono::{DateTime, Utc}; use log::warn; -use enums::by_table::favorites::favorite_entity_type::FavoriteEntityType; -use mysql_queries::queries::favorites::list_user_favorites::{list_user_favorites, list_user_favorites_by_entity_type}; -use tokens::tokens::favorites::FavoriteToken; +use enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType; +use mysql_queries::queries::user_bookmarks::list_user_bookmarks::{list_user_bookmarks, list_user_user_bookmarks_by_entity_type}; +use tokens::tokens::user_bookmarks::UserBookmarkToken; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; use crate::server_state::ServerState; #[derive(Deserialize)] -pub struct ListFavoritesQueryData { - maybe_scoped_entity_type: Option, +pub struct ListUserBookmarksQueryData { + maybe_scoped_entity_type: Option, } #[derive(Serialize)] -pub struct ListFavoritesSuccessResponse { +pub struct ListUserBookmarksSuccessResponse { pub success: bool, - pub favorites: Vec, + pub user_bookmarks: Vec, } #[derive(Serialize)] -pub struct Favorite { - pub token: FavoriteToken, +pub struct UserBookmark { + pub token: UserBookmarkToken, - pub details: FavoriteDetails, + pub details: UserBookmarkDetails, pub created_at: DateTime, pub updated_at: DateTime, } #[derive(Serialize)] -pub struct FavoriteDetails { +pub struct UserBookmarkDetails { // TODO: This needs titles or some other summary metadata. - pub entity_type: FavoriteEntityType, + pub entity_type: UserBookmarkEntityType, pub entity_token: String, // TODO: Populate this for TTS @@ -55,23 +55,23 @@ pub struct FavoriteDetails { } #[derive(Debug)] -pub enum ListFavoritesError { +pub enum ListUserBookmarksError { ServerError, NotAuthorizedError, } -impl ResponseError for ListFavoritesError { +impl ResponseError for ListUserBookmarksError { fn status_code(&self) -> StatusCode { match *self { - ListFavoritesError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, - ListFavoritesError::NotAuthorizedError => StatusCode::UNAUTHORIZED, + ListUserBookmarksError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, + ListUserBookmarksError::NotAuthorizedError => StatusCode::UNAUTHORIZED, } } fn error_response(&self) -> HttpResponse { let error_reason = match self { - ListFavoritesError::ServerError => "server error".to_string(), - ListFavoritesError::NotAuthorizedError => "not authorized".to_string(), + ListUserBookmarksError::ServerError => "server error".to_string(), + ListUserBookmarksError::NotAuthorizedError => "not authorized".to_string(), }; to_simple_json_error(&error_reason, self.status_code()) @@ -79,61 +79,61 @@ impl ResponseError for ListFavoritesError { } // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for ListFavoritesError { +impl fmt::Display for ListUserBookmarksError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:?}", self) } } -pub async fn list_favorites_for_session_handler( +pub async fn list_user_bookmarks_for_session_handler( http_request: HttpRequest, - query: Query, + query: Query, server_state: web::Data> -) -> Result +) -> Result { let user_session = server_state.session_checker .maybe_get_user_session(&http_request, &server_state.mysql_pool) .await .map_err(|e| { warn!("Session checker error: {:?}", e); - ListFavoritesError::ServerError + ListUserBookmarksError::ServerError })? - .ok_or(ListFavoritesError::NotAuthorizedError)?; + .ok_or(ListUserBookmarksError::NotAuthorizedError)?; let query_results = match query.maybe_scoped_entity_type { - None => list_user_favorites(&user_session.username, &server_state.mysql_pool).await, + None => list_user_bookmarks(&user_session.username, &server_state.mysql_pool).await, Some(entity_type) => - list_user_favorites_by_entity_type(&user_session.username, entity_type, &server_state.mysql_pool) + list_user_user_bookmarks_by_entity_type(&user_session.username, entity_type, &server_state.mysql_pool) .await, }; - let favorites = match query_results { + let user_bookmarks = match query_results { Ok(results) => results, Err(e) => { warn!("Query error: {:?}", e); - return Err(ListFavoritesError::ServerError); + return Err(ListUserBookmarksError::ServerError); } }; - let response = ListFavoritesSuccessResponse { + let response = ListUserBookmarksSuccessResponse { success: true, - favorites: favorites.into_iter() - .map(|favorite| Favorite { - token: favorite.token, - details: FavoriteDetails { - entity_type: favorite.entity_type, - entity_token: favorite.entity_token, + user_bookmarks: user_bookmarks.into_iter() + .map(|user_bookmark| UserBookmark { + token: user_bookmark.token, + details: UserBookmarkDetails { + entity_type: user_bookmark.entity_type, + entity_token: user_bookmark.entity_token, maybe_summary_text: None, maybe_thumbnail_url: None, }, - created_at: favorite.created_at, - updated_at: favorite.updated_at, + created_at: user_bookmark.created_at, + updated_at: user_bookmark.updated_at, }) .collect(), }; let body = serde_json::to_string(&response) - .map_err(|_e| ListFavoritesError::ServerError)?; + .map_err(|_e| ListUserBookmarksError::ServerError)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/favorites/list_favorites_for_user_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/list_user_bookmarks_for_user_handler.rs similarity index 51% rename from crates/service/web/storyteller_web/src/http_server/endpoints/favorites/list_favorites_for_user_handler.rs rename to crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/list_user_bookmarks_for_user_handler.rs index 071b1fcb0e..ccaf8b61f4 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/favorites/list_favorites_for_user_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/list_user_bookmarks_for_user_handler.rs @@ -13,43 +13,43 @@ use actix_web::web::{Path, Query}; use chrono::{DateTime, Utc}; use log::warn; -use enums::by_table::favorites::favorite_entity_type::FavoriteEntityType; -use mysql_queries::queries::favorites::list_user_favorites::{list_user_favorites, list_user_favorites_by_entity_type}; -use tokens::tokens::favorites::FavoriteToken; +use enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType; +use mysql_queries::queries::user_bookmarks::list_user_bookmarks::{list_user_bookmarks, list_user_user_bookmarks_by_entity_type}; +use tokens::tokens::user_bookmarks::UserBookmarkToken; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; use crate::server_state::ServerState; #[derive(Deserialize)] -pub struct ListFavoritesPathInfo { +pub struct ListUserBookmarksPathInfo { username: String, } #[derive(Deserialize)] -pub struct ListFavoritesQueryData { - maybe_scoped_entity_type: Option, +pub struct ListUserBookmarksQueryData { + maybe_scoped_entity_type: Option, } #[derive(Serialize)] -pub struct ListFavoritesSuccessResponse { +pub struct ListUserBookmarksSuccessResponse { pub success: bool, - pub favorites: Vec, + pub user_bookmarks: Vec, } #[derive(Serialize)] -pub struct Favorite { - pub token: FavoriteToken, +pub struct UserBookmark { + pub token: UserBookmarkToken, - pub details: FavoriteDetails, + pub details: UserBookmarkDetails, pub created_at: DateTime, pub updated_at: DateTime, } #[derive(Serialize)] -pub struct FavoriteDetails { +pub struct UserBookmarkDetails { // TODO: This needs titles or some other summary metadata. - pub entity_type: FavoriteEntityType, + pub entity_type: UserBookmarkEntityType, pub entity_token: String, // TODO: Populate this for TTS @@ -60,20 +60,20 @@ pub struct FavoriteDetails { } #[derive(Debug)] -pub enum ListFavoritesError { +pub enum ListUserBookmarksError { ServerError, } -impl ResponseError for ListFavoritesError { +impl ResponseError for ListUserBookmarksError { fn status_code(&self) -> StatusCode { match *self { - ListFavoritesError::ServerError=> StatusCode::INTERNAL_SERVER_ERROR, + ListUserBookmarksError::ServerError=> StatusCode::INTERNAL_SERVER_ERROR, } } fn error_response(&self) -> HttpResponse { let error_reason = match self { - ListFavoritesError::ServerError => "server error".to_string(), + ListUserBookmarksError::ServerError => "server error".to_string(), }; to_simple_json_error(&error_reason, self.status_code()) @@ -81,56 +81,56 @@ impl ResponseError for ListFavoritesError { } // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for ListFavoritesError { +impl fmt::Display for ListUserBookmarksError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:?}", self) } } -pub async fn list_favorites_for_user_handler( +pub async fn list_user_bookmarks_for_user_handler( _http_request: HttpRequest, - path: Path, - query: Query, + path: Path, + query: Query, server_state: web::Data> -) -> Result +) -> Result { let query_results = match query.maybe_scoped_entity_type { - None => list_user_favorites(&path.username, &server_state.mysql_pool).await, + None => list_user_bookmarks(&path.username, &server_state.mysql_pool).await, Some(entity_type) => - list_user_favorites_by_entity_type(&path.username, entity_type, &server_state.mysql_pool) + list_user_user_bookmarks_by_entity_type(&path.username, entity_type, &server_state.mysql_pool) .await, }; - let favorites = match query_results { + let user_bookmarks = match query_results { Ok(results) => results, Err(e) => { warn!("Query error: {:?}", e); - return Err(ListFavoritesError::ServerError); + return Err(ListUserBookmarksError::ServerError); } }; - let response = ListFavoritesSuccessResponse { + let response = ListUserBookmarksSuccessResponse { success: true, - favorites: favorites.into_iter() - .map(|favorite| Favorite { - token: favorite.token, - details: FavoriteDetails { - entity_type: favorite.entity_type, - entity_token: favorite.entity_token, - maybe_summary_text: favorite.maybe_entity_descriptive_text, + user_bookmarks: user_bookmarks.into_iter() + .map(|user_bookmark| UserBookmark { + token: user_bookmark.token, + details: UserBookmarkDetails { + entity_type: user_bookmark.entity_type, + entity_token: user_bookmark.entity_token, + maybe_summary_text: user_bookmark.maybe_entity_descriptive_text, // TODO(bt,2023-11-21): Thumbnails need proper support. We should build them as a // first-class system before handling the backfill here. maybe_thumbnail_url: None, }, - created_at: favorite.created_at, - updated_at: favorite.updated_at, + created_at: user_bookmark.created_at, + updated_at: user_bookmark.updated_at, }) .collect(), }; let body = serde_json::to_string(&response) - .map_err(|_e| ListFavoritesError::ServerError)?; + .map_err(|_e| ListUserBookmarksError::ServerError)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/mod.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/mod.rs new file mode 100644 index 0000000000..11881f5bb3 --- /dev/null +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/mod.rs @@ -0,0 +1,5 @@ +pub mod create_user_bookmark_handler; +pub mod delete_user_bookmark_handler; +pub mod list_user_bookmarks_for_entity_handler; +pub mod list_user_bookmarks_for_session_handler; +pub mod list_user_bookmarks_for_user_handler; diff --git a/crates/service/web/storyteller_web/src/routes.rs b/crates/service/web/storyteller_web/src/routes.rs index eb67880dd5..9dcdce3e35 100644 --- a/crates/service/web/storyteller_web/src/routes.rs +++ b/crates/service/web/storyteller_web/src/routes.rs @@ -28,11 +28,11 @@ use crate::http_server::endpoints::comments::list_comments_handler::list_comment use crate::http_server::endpoints::download_job::enqueue_generic_download::enqueue_generic_download_handler; use crate::http_server::endpoints::download_job::get_generic_upload_job_status::get_generic_download_job_status_handler; use crate::http_server::endpoints::events::list_events::list_events_handler; -use crate::http_server::endpoints::favorites::create_favorite_handler::create_favorite_handler; -use crate::http_server::endpoints::favorites::delete_favorite_handler::delete_favorite_handler; -use crate::http_server::endpoints::favorites::list_favorites_for_entity_handler::list_favorites_for_entity_handler; -use crate::http_server::endpoints::favorites::list_favorites_for_session_handler::list_favorites_for_session_handler; -use crate::http_server::endpoints::favorites::list_favorites_for_user_handler::list_favorites_for_user_handler; +use crate::http_server::endpoints::user_bookmarks::create_user_bookmark_handler::create_user_bookmark_handler; +use crate::http_server::endpoints::user_bookmarks::delete_user_bookmark_handler::delete_user_bookmark_handler; +use crate::http_server::endpoints::user_bookmarks::list_user_bookmarks_for_entity_handler::list_user_bookmarks_for_entity_handler; +use crate::http_server::endpoints::user_bookmarks::list_user_bookmarks_for_session_handler::list_user_bookmarks_for_session_handler; +use crate::http_server::endpoints::user_bookmarks::list_user_bookmarks_for_user_handler::list_user_bookmarks_for_user_handler; use crate::http_server::endpoints::flags::design_refresh_flag::disable_design_refresh_flag_handler::disable_design_refresh_flag_handler; use crate::http_server::endpoints::flags::design_refresh_flag::enable_design_refresh_flag_handler::enable_design_refresh_flag_handler; use crate::http_server::endpoints::inference_job::get_inference_job_status::get_inference_job_status_handler; @@ -202,14 +202,14 @@ pub fn add_routes (app: App, server_environment: ServerEnvironment) -> .add_post("/v1/comments/delete/{comment_token}", delete_comment_handler) .into_app(); - // ==================== Favorites ==================== + // ==================== User Bookmarks ==================== let mut app = RouteBuilder::from_app(app) - .add_post("/v1/favorites/create", create_favorite_handler) - .add_post("/v1/favorites/delete/{favorite_token}", delete_favorite_handler) - .add_get("/v1/favorites/list/session", list_favorites_for_session_handler) - .add_get("/v1/favorites/list/user/{username}", list_favorites_for_user_handler) - .add_get("/v1/favorites/list/entity/{entity_type}/{entity_token}", list_favorites_for_entity_handler) + .add_post("/v1/user_bookmarks/create", create_user_bookmark_handler) + .add_post("/v1/user_bookmarks/delete/{user_bookmark_token}", delete_user_bookmark_handler) + .add_get("/v1/user_bookmarks/list/session", list_user_bookmarks_for_session_handler) + .add_get("/v1/user_bookmarks/list/user/{username}", list_user_bookmarks_for_user_handler) + .add_get("/v1/user_bookmarks/list/entity/{entity_type}/{entity_token}", list_user_bookmarks_for_entity_handler) .into_app(); // ==================== Animations ==================== From e78cdf85e30ead4cca5b6cbe92404493679f1a71 Mon Sep 17 00:00:00 2001 From: Michael Chung Date: Mon, 11 Dec 2023 14:40:14 -0500 Subject: [PATCH 008/124] Upload weights front end side done, need to write the download code then run inference depending on the model. --- crates/lib/deprecated/config/src/bad_urls.rs | 5 + .../drain_multipart_weights_request.rs | 100 ----- .../endpoints/weights/upload_weight.rs | 385 +++++++----------- 3 files changed, 158 insertions(+), 332 deletions(-) delete mode 100644 crates/service/web/storyteller_web/src/http_server/endpoints/weights/drain_multipart_weights_request.rs diff --git a/crates/lib/deprecated/config/src/bad_urls.rs b/crates/lib/deprecated/config/src/bad_urls.rs index 13be46019b..280ed1d3bb 100644 --- a/crates/lib/deprecated/config/src/bad_urls.rs +++ b/crates/lib/deprecated/config/src/bad_urls.rs @@ -3,11 +3,16 @@ use crate::is_bad_download_url::is_bad_download_url; /// Reports if the URL is inappropriate for downloading as a TTS model, vocoder, etc. +/// DEPRECATE: pub fn is_bad_tts_model_download_url(url: &str) -> anyhow::Result { // TODO: Just use this. is_bad_download_url(url) } +pub fn is_bad_model_weights_download_url(url: &str) -> anyhow::Result { + is_bad_download_url(url) +} + #[cfg(test)] mod tests { use crate::bad_urls::is_bad_tts_model_download_url; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/drain_multipart_weights_request.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/drain_multipart_weights_request.rs deleted file mode 100644 index c87a9d82c5..0000000000 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/drain_multipart_weights_request.rs +++ /dev/null @@ -1,100 +0,0 @@ -use actix_multipart::Multipart; -use actix_web::web::BytesMut; -use futures::TryStreamExt; -use log::warn; - -use errors::AnyhowResult; -use tokens::tokens::weights::ModelWeightToken; - -use crate::http_server::web_utils::read_multipart_field_bytes::{checked_read_multipart_bytes, read_multipart_field_as_text}; - -pub struct WeightUploadRequest { - pub uuid_idempotency_token: Option, - pub model_weights_token: Option, - pub file_name: Option, - pub file_bytes: Option, - pub media_source: MediaSource, -} - -/// Where the frontend tells us the file came from. -#[derive(Eq, PartialEq, Clone, Copy)] -pub enum MediaSource { - Unknown, - UserFile, - /// Eg. the web audio API in Javascript. - UserDeviceApi, -} - -/// Pull common parts out of multipart media HTTP requests, typically for handling file uploads. -pub async fn drain_multipart_request(mut multipart_payload: Multipart) -> AnyhowResult { - let mut uuid_idempotency_token = None; - let mut model_weight_token = None; - let mut file_bytes = None; - let mut file_name = None; - let mut media_source = None; - - while let Ok(Some(mut field)) = multipart_payload.try_next().await { - let mut field_name = None; - let mut field_filename = None; - - if let content_disposition = field.content_disposition() { - field_name = content_disposition.get_name() - .map(|s| s.to_string()); - field_filename = content_disposition.get_filename() // NB: Only used for the file bytes. - .map(|s| s.to_string()); - } - - match field_name.as_deref() { - Some("uuid_idempotency_token") => { - uuid_idempotency_token = read_multipart_field_as_text(&mut field).await - .map_err(|e| { - warn!("Error reading idempotency token: {:}", e); - e - })?; - }, - Some("dataset_token") => { - model_weight_token = read_multipart_field_as_text(&mut field).await - .map_err(|e| { - warn!("Error reading dataset token: {:}", e); - e - })?; - }, - Some("file") => { - file_name = field_filename.clone(); - file_bytes = checked_read_multipart_bytes(&mut field).await - .map_err(|e| { - warn!("Error reading audio upload: {:}", e); - e - })?; - }, - Some("source") => { - media_source = read_multipart_field_as_text(&mut field).await - .map_err(|e| { - warn!("Error reading source: {:}", e); - e - })?; - }, - _ => continue, - } - } - - let media_source = match media_source.as_deref() { - Some("device") => MediaSource::UserDeviceApi, - Some("file") => MediaSource::UserFile, - _ => { - if file_name.as_deref() == Some("blob") { - MediaSource::UserDeviceApi - } else { - MediaSource::Unknown - } - }, - }; - - Ok(UploadSampleRequest { - uuid_idempotency_token, - dataset_token, - file_name, - file_bytes, - media_source, - }) -} diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/upload_weight.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/upload_weight.rs index 2d66aa7684..8d2aa5fc5c 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/upload_weight.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/upload_weight.rs @@ -2,10 +2,10 @@ use std::collections::HashSet; use std::sync::Arc; use actix_multipart::Multipart; -use actix_web::{HttpRequest, HttpResponse, web}; +use actix_web::{ HttpRequest, HttpResponse, web }; use enums::by_table::model_weights::weights_category::WeightsCategory; use enums::by_table::model_weights::weights_types::WeightsType; -use mysql_queries::queries::model_weights::create_weight::{self, create_weight}; +use mysql_queries::queries::model_weights::create_weight::{ self, create_weight }; use once_cell::sync::Lazy; use tokens::tokens::model_weights::ModelWeightToken; @@ -13,259 +13,180 @@ use tokens::tokens::model_weights::ModelWeightToken; use crate::http_server::endpoints::media_uploads::common::upload_error::UploadError; use crate::server_state::ServerState; -use log::{error, info, warn}; +use log::{ error, info, warn }; use buckets::public::weight_uploads::original_file::WeightUploadOriginalFilePath; use enums::by_table::media_uploads::media_upload_source::MediaUploadSource; use enums::by_table::media_uploads::media_upload_type::MediaUploadType; -use enums::common::visibility::Visibility; + use hashing::sha256::sha256_hash_bytes::sha256_hash_bytes; use http_server_common::request::get_request_ip::get_request_ip; use media::decode_basic_audio_info::decode_basic_audio_bytes_info; use mimetypes::mimetype_for_bytes::get_mimetype_for_bytes; use mysql_queries::queries::media_uploads::get_media_upload_by_uuid::get_media_upload_by_uuid_with_connection; -use mysql_queries::queries::media_uploads::insert_media_upload::{Args, insert_media_upload}; +use mysql_queries::queries::media_uploads::insert_media_upload::{ Args, insert_media_upload }; -use crate::http_server::endpoints::media_uploads::common::drain_multipart_request::{drain_multipart_request, MediaSource}; +use crate::http_server::endpoints::media_uploads::common::drain_multipart_request::{ + drain_multipart_request, + MediaSource, +}; use crate::validations::validate_idempotency_token_format::validate_idempotency_token_format; use utoipa::ToSchema; +use config::bad_urls::is_bad_model_weights_download_url; + +use enums::by_table::model_weights::{ + weights_category::WeightsCategory, + weights_types::WeightsType, +}; +use enums::common::visibility::Visibility; +use utoipa::ToSchema; + +#[derive(Deserialize, ToSchema)] +pub struct UploadModelWeightsRequest { + idempotency_token: String, + title: String, + download_url: String, + model_weights_type: WeightsType, + model_weights_category: WeightsCategory, + creator_set_visibility: Option, +} + +/// Tell the frontend how to deal with the download queue. +#[derive(Serialize, ToSchema)] +pub enum DownloadJobType { + /// Modern shared download type (everything will use this in the + /// future, and this endpoint will die.) + #[serde(rename = "generic")] + Generic, +} + +#[derive(Serialize, ToSchema)] +pub struct UploadModelWeightsSuccessResponse { + pub success: bool, + /// This is how frontend clients can request the job execution status. + pub job_token: String, + /// This is a transitional field to tell the frontend how to process the job checking. + pub job_type: DownloadJobType, +} + +#[derive(Debug)] +pub enum UploadModelWeightsError { + BadInput(String), + MustBeLoggedIn, + ServerError, + RateLimited, +} + +impl ResponseError for UploadModelWeightsError { + fn status_code(&self) -> StatusCode { + match *self { + UploadModelWeightsError::BadInput(_) => StatusCode::BAD_REQUEST, + UploadModelWeightsError::MustBeLoggedIn => StatusCode::UNAUTHORIZED, + UploadModelWeightsError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, + UploadModelWeightsError::RateLimited => StatusCode::TOO_MANY_REQUESTS, + } + } + + fn error_response(&self) -> HttpResponse { + let error_reason = match self { + UploadModelWeightsError::BadInput(reason) => reason.to_string(), + UploadModelWeightsError::MustBeLoggedIn => "user must be logged in".to_string(), + UploadModelWeightsError::ServerError => "server error".to_string(), + UploadModelWeightsError::RateLimited => "rate limited".to_string(), + }; + + to_simple_json_error(&error_reason, self.status_code()) + } +} + pub async fn upload_weights_handler( http_request: HttpRequest, server_state: web::Data>, - mut multipart_payload: Multipart, - ) -> Result { - - let response = handle_weight_upload( - &http_request, - &server_state, - multipart_payload, - &ALLOWED_MIME_TYPES).await?; - - // send a body with the required payload along side the multipart upload - - let weight_upload_token = response.to_model_token(); - - let response: UploadWeightsSuccessResponse = UploadWeightsSuccessResponse { - success: true, - upload_token: weight_upload_token, - }; - - let body = serde_json::to_string(&response) - .map_err(|e| UploadError::ServerError)?; - - return Ok(HttpResponse::Ok() - .content_type("application/json") - .body(body)); - } - - pub enum SuccessCase { - WeightAlreadyUploaded { - existing_upload_token: ModelWeightToken, - }, - WeightSuccessfullyUploaded { - upload_token: ModelWeightToken, + mut multipart_payload: Multipart +) -> Result { + // Rate limiter check + if + let Err(_err) = server_state.redis_rate_limiters.model_upload.rate_limit_request( + &http_request + ) + { + return Err(UploadModelWeightsError::RateLimited); } - } - - impl SuccessCase { - pub fn to_model_token(self) -> ModelWeightToken { - match self { - SuccessCase::WeightAlreadyUploaded { existing_upload_token } => existing_upload_token, - SuccessCase::WeightSuccessfullyUploaded { upload_token } => upload_token, - } - } - } - - pub async fn handle_weight_upload( - http_request: &HttpRequest, - server_state: &web::Data>, - mut multipart_payload: Multipart, - allowed_mimetypes: &HashSet<&'static str>, - ) -> Result { - - let mut mysql_connection = server_state.mysql_pool - .acquire() - .await - .map_err(|err| { - error!("MySql pool error: {:?}", err); - UploadError::ServerError - })?; - - // ==================== READ SESSION ==================== // - - let maybe_user_session = server_state - .session_checker - .maybe_get_user_session_from_connection(http_request, &mut mysql_connection) - .await + + let maybe_user_session = server_state.session_checker + .maybe_get_user_session(&http_request, &server_state.mysql_pool).await .map_err(|e| { - error!("Session checker error: {:?}", e); - UploadError::ServerError + warn!("Session checker error: {:?}", e); + UploadModelWeightsError::ServerError })?; - - // ==================== RATE LIMIT ==================== // - - let rate_limiter = match maybe_user_session { - None => &server_state.redis_rate_limiters.logged_out, - Some(ref user) => { - if user.is_banned { - return Err(UploadError::NotAuthorized); + + let user_session = match maybe_user_session { + Some(session) => session, + None => { + warn!("not logged in"); + return Err(UploadModelWeightsError::MustBeLoggedIn); } - &server_state.redis_rate_limiters.logged_in - }, }; - - if let Err(_err) = rate_limiter.rate_limit_request(&http_request) { - return Err(UploadError::RateLimited); + + if let Err(reason) = validate_idempotency_token(&request.idempotency_token) { + return Err(UploadModelWeightsError::BadInput(reason)); } - - if let Err(_err) = server_state.redis_rate_limiters.model_upload.rate_limit_request(&http_request) { - return Err(UploadError::RateLimited); + + if let Err(reason) = validate_model_title(&request.title) { + return Err(UploadModelWeightsError::BadInput(reason)); } - - // ==================== READ MULTIPART REQUEST ==================== // - - let upload_weights_request = drain_multipart_request(multipart_payload) - .await - .map_err(|e| { - // TODO: Error handling could be nicer. - UploadError::BadInput("bad request".to_string()) - })?; - - let uuid_idempotency_token = upload_weights_request.uuid_idempotency_token - .ok_or(UploadError::BadInput("no uuid".to_string()))?; - - let maybe_existing_upload = - get_media_upload_by_uuid_with_connection(&uuid_idempotency_token, &mut mysql_connection) - .await; - - match maybe_existing_upload { - Err(err) => { - error!("Error checking for previous upload: {:?}", err); - return Err(UploadError::ServerError); - } - Ok(Some(upload)) => { - // File already uploaded and frontend didn't protect us. - return Ok(SuccessCase::WeightAlreadyUploaded { - existing_upload_token: upload.token, - }); - } - Ok(None) => { - // Proceed. - } + + match is_bad_model_weights_download_url(&download_url) { + Ok(false) => {} // Ok case + Ok(true) => { + return Err(UploadModelWeightsError::BadInput("Bad model download URL".to_string())); + } + Err(err) => { + warn!("Error parsing url: {:?}", err); + return Err(UploadModelWeightsError::BadInput("Bad model download URL".to_string())); + } } - - if let Err(reason) = validate_idempotency_token_format(&uuid_idempotency_token) { - return Err(UploadError::BadInput(reason)); - } - - let creator_set_visibility = maybe_user_session - .as_ref() - .map(|user_session| user_session.preferred_tts_result_visibility) // TODO: We need a new type of visibility control. - .unwrap_or(Visibility::default()); - - let ip_address = get_request_ip(&http_request); - - let maybe_user_token = maybe_user_session - .map(|session| session.get_strongly_typed_user_token()); - - let maybe_file_size_bytes = upload_weights_request.file_bytes - .as_ref() - .map(|bytes| bytes.len()); - - info!("Upload maybe filesize: {:?}", maybe_file_size_bytes); - - let maybe_mimetype = upload_weights_request.file_bytes - .as_ref() - .map(|bytes| get_mimetype_for_bytes(bytes.as_ref())) - .flatten(); - - - let bytes = match upload_weights_request.file_bytes { - None => return Err(UploadError::BadInput("missing file contents".to_string())), - Some(bytes) => bytes, + + let supported_model_weights_type = request.model_weights_type; + + let job_token; + let download_job_type; + + let (download_job_token, _record_id) = insert_generic_download_job( + InsertGenericDownloadJobArgs { + uuid_idempotency_token: &uuid, + download_type: GenericDownloadType::Vits, + download_url: &download_url, + title: &title, + creator_user_token: &user_session.user_token, + creator_ip_address: &ip_address, + creator_set_visibility: visibility, // TODO: Creator set preference + mysql_pool: &server_state.mysql_pool, + } + ).await.map_err(|err| { + warn!("New generic download creation DB error (for generic model): {:?}", err); + UploadModelWeightsError::ServerError + })?; + + job_token = download_job_token.to_string(); + download_job_type = DownloadJobType::Generic; + + let response = UploadModelWeightsSuccessResponse { + success: true, + job_token: job_token.to_string(), + job_type: download_job_type, }; - - let hash = sha256_hash_bytes(&bytes) - .map_err(|io_error| { - error!("Problem hashing bytes: {:?}", io_error); - UploadError::ServerError - })?; - - let file_size_bytes = bytes.len(); - - let mut maybe_duration_millis = None; - let mut maybe_codec_name = None; - let mut media_upload_type = None; - - if let Some(mimetype) = maybe_mimetype.as_deref() { - - if !allowed_mimetypes.contains(mimetype) { - // NB: Don't let our error message inject malicious strings - let filtered_mimetype = mimetype - .chars() - .filter(|c| c.is_ascii()) - .filter(|c| c.is_alphanumeric() || *c == '/') - .collect::(); - return Err(UploadError::BadInput(format!("unpermitted mime type: {}", &filtered_mimetype))); - } - media_upload_type = match mimetype { - "binary/octet-stream" /* .bin */ => Some(MediaUploadType::Binary), - _ => None, - }; + + let body = serde_json::to_string(&response).map_err(|_e| UploadModelWeightsError::ServerError)?; + + Ok(HttpResponse::Ok().content_type("application/json").body(body)) +} + +fn validate_idempotency_token(token: &str) -> Result<(), String> { + if token.len() != 36 { + return Err("idempotency token should be 36 characters".to_string()); } - - // This is fine for now we just don't expose the path! - let public_upload_path = WeightUploadOriginalFilePath::generate_new(); - - info!("Uploading media to bucket path: {}", public_upload_path.get_full_object_path_str()); - - // need to upload based on visibility - server_state.public_bucket_client.upload_file_with_content_type( - public_upload_path.get_full_object_path_str(), - bytes.as_ref(), - mime_type) - .await - .map_err(|e| { - warn!("Upload media bytes to bucket error: {:?}", e); - UploadError::ServerError - })?; - - let token = create_weight(CreateModelWeightsArgs { - token: &ModelWeightToken::generate(), - weights_type: WeightsType::LoRA, // to do parse multi part for this - weights_category: WeightsCategory::ImageGeneration, - title: upload_weights_request.file_name.as_deref(), - maybe_thumbnail_token: &ThumbnailToken::generate(), - description_markdown: "", - description_rendered_html: "", - creator_user_token: maybe_user_token.as_str(), - creator_ip_address: &ip_address, - creator_set_visibility, - maybe_last_update_user_token: "", - original_download_url: "", - original_filename: upload_weights_request.file_name.as_deref(), - file_size_bytes: file_size_bytes as i32, - file_checksum_sha2: hash, - private_bucket_hash: private_bucket_hash, - maybe_private_bucket_prefix: None, - maybe_private_bucket_extension: None, - cached_user_ratings_total_count: 0, - cached_user_ratings_positive_count: 0, - cached_user_ratings_negative_count: 0, - maybe_cached_user_ratings_ratio: None, - version: 0, - mysql_pool: &server_state.mysql_pool, - }).await - .map_err(|e| { - error!("Error creating weights upload: {:?}", e); - UploadError::ServerError - })?; - - info!("new weights upload id: {} token: {:?}", record_id, &token); - - Ok(SuccessCase::WeightSuccessfullyUploaded { - upload_token: token, - }) - } - \ No newline at end of file + + Ok(()) +} From c09adc3729ea697a032db6172b330e8d78c3fa8b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Dec 2023 22:08:50 +0000 Subject: [PATCH 009/124] Bump hyper-tls from 0.5.0 to 0.6.0 Bumps [hyper-tls](https://github.com/hyperium/hyper-tls) from 0.5.0 to 0.6.0. - [Commits](https://github.com/hyperium/hyper-tls/compare/v0.5.0...v0.6.0) --- updated-dependencies: - dependency-name: hyper-tls dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Cargo.lock | 172 ++++++++++++++---- .../newrelic-telemetry-sdk-rust/Cargo.toml | 2 +- 2 files changed, 141 insertions(+), 33 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1aaf8d3a68..9182c02682 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -103,7 +103,7 @@ dependencies = [ "flate2", "futures-core", "h2", - "http", + "http 0.2.11", "httparse", "httpdate", "itoa 1.0.9", @@ -176,7 +176,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66ff4d247d2b160861fa2866457e85706833527840e4133f8f49aa423a38799" dependencies = [ "bytestring", - "http", + "http 0.2.11", "regex", "serde", "tracing", @@ -614,8 +614,8 @@ dependencies = [ "hex", "hmac 0.12.1", "http-types", - "hyper", - "hyper-tls", + "hyper 0.14.27", + "hyper-tls 0.5.0", "serde", "serde_json", "serde_path_to_error", @@ -676,7 +676,7 @@ version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fcf00bc6d5abb29b5f97e3c61a90b6d3caa12f3faf897d4a3e3607c050a35a7" dependencies = [ - "http", + "http 0.2.11", "log", "native-tls", "serde", @@ -1961,7 +1961,7 @@ dependencies = [ "google_drive_common", "hashing", "hostname", - "hyper", + "hyper 0.14.27", "jobs_common", "log", "mimetypes", @@ -2151,7 +2151,7 @@ dependencies = [ "filesys", "hashing", "hostname", - "hyper", + "hyper 0.14.27", "images", "jobs_common", "lfu", @@ -2636,7 +2636,7 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http", + "http 0.2.11", "indexmap", "slab", "tokio 1.34.0", @@ -2796,6 +2796,17 @@ dependencies = [ "itoa 1.0.9", ] +[[package]] +name = "http" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea" +dependencies = [ + "bytes 1.5.0", + "fnv", + "itoa 1.0.9", +] + [[package]] name = "http-body" version = "0.4.5" @@ -2803,7 +2814,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes 1.5.0", - "http", + "http 0.2.11", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" +dependencies = [ + "bytes 1.5.0", + "http 1.0.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41cb79eb393015dadd30fc252023adb0b2400a0caee0fa2a077e6e21a551e840" +dependencies = [ + "bytes 1.5.0", + "futures-util", + "http 1.0.0", + "http-body 1.0.0", "pin-project-lite", ] @@ -2823,7 +2857,7 @@ dependencies = [ "async-channel", "base64 0.13.1", "futures-lite", - "http", + "http 0.2.11", "infer 0.2.3", "pin-project-lite", "rand 0.7.3", @@ -2887,8 +2921,8 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", - "http-body", + "http 0.2.11", + "http-body 0.4.5", "httparse", "httpdate", "itoa 1.0.9", @@ -2900,6 +2934,22 @@ dependencies = [ "want", ] +[[package]] +name = "hyper" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "403f9214f3e703236b221f1a9cd88ec8b4adfa5296de01ab96216361f4692f56" +dependencies = [ + "bytes 1.5.0", + "futures-channel", + "futures-util", + "http 1.0.0", + "http-body 1.0.0", + "pin-project-lite", + "tokio 1.34.0", + "want", +] + [[package]] name = "hyper-tls" version = "0.5.0" @@ -2907,12 +2957,48 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes 1.5.0", - "hyper", + "hyper 0.14.27", "native-tls", "tokio 1.34.0", "tokio-native-tls", ] +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes 1.5.0", + "http-body-util", + "hyper 1.0.1", + "hyper-util", + "native-tls", + "tokio 1.34.0", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ca339002caeb0d159cc6e023dff48e199f081e42fa039895c7c6f38b37f2e9d" +dependencies = [ + "bytes 1.5.0", + "futures-channel", + "futures-util", + "http 1.0.0", + "http-body 1.0.0", + "hyper 1.0.1", + "pin-project-lite", + "socket2 0.5.5", + "tokio 1.34.0", + "tower", + "tower-service", + "tracing", +] + [[package]] name = "iana-time-zone" version = "0.1.58" @@ -3057,7 +3143,7 @@ dependencies = [ "filesys", "hashing", "hostname", - "hyper", + "hyper 0.14.27", "images", "jobs_common", "lfu", @@ -3758,7 +3844,7 @@ dependencies = [ "hashbrown 0.14.2", "heck", "hmac 0.12.1", - "hyper", + "hyper 0.14.27", "indexmap", "lazy_static", "libc", @@ -3897,8 +3983,8 @@ dependencies = [ "env_logger", "flate2", "futures 0.3.29", - "hyper", - "hyper-tls", + "hyper 0.14.27", + "hyper-tls 0.6.0", "log", "my-workspace-hack", "rand 0.8.5", @@ -4905,10 +4991,10 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http", - "http-body", - "hyper", - "hyper-tls", + "http 0.2.11", + "http-body 0.4.5", + "hyper 0.14.27", + "hyper-tls 0.5.0", "ipnet", "js-sys", "log", @@ -5066,7 +5152,7 @@ dependencies = [ "futures 0.3.29", "hex", "hmac 0.12.1", - "http", + "http 0.2.11", "log", "maybe-async", "md5", @@ -6027,7 +6113,7 @@ dependencies = [ "hmac 0.10.1", "hostname", "http_server_common", - "hyper", + "hyper 0.14.27", "infer 0.5.0", "jwt", "language-tags", @@ -6867,6 +6953,28 @@ dependencies = [ "serde", ] +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio 1.34.0", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + [[package]] name = "tower-service" version = "0.3.2" @@ -6927,7 +7035,7 @@ dependencies = [ "google_drive_common", "hashing", "hostname", - "hyper", + "hyper 0.14.27", "jobs_common", "log", "my-workspace-hack", @@ -6958,7 +7066,7 @@ dependencies = [ "filesys", "hashing", "hostname", - "hyper", + "hyper 0.14.27", "jobs_common", "lfu", "log", @@ -7003,7 +7111,7 @@ dependencies = [ "base64 0.13.1", "byteorder", "bytes 1.5.0", - "http", + "http 0.2.11", "httparse", "log", "rand 0.8.5", @@ -7033,7 +7141,7 @@ dependencies = [ "futures 0.3.29", "futures-util", "hostname", - "hyper", + "hyper 0.14.27", "lazy_static", "log", "magic-crypt", @@ -7075,7 +7183,7 @@ dependencies = [ "chrono", "displaydoc", "futures 0.3.29", - "http", + "http 0.2.11", "once_cell", "reqwest", "serde", @@ -7115,7 +7223,7 @@ dependencies = [ "async-trait", "base64 0.13.1", "displaydoc", - "http", + "http 0.2.11", "once_cell", "rand 0.8.5", "reqwest", @@ -7437,7 +7545,7 @@ dependencies = [ "google_drive_common", "hashing", "hostname", - "hyper", + "hyper 0.14.27", "jobs_common", "log", "my-workspace-hack", @@ -7466,7 +7574,7 @@ dependencies = [ "filesys", "google_drive_common", "hostname", - "hyper", + "hyper 0.14.27", "jobs_common", "log", "my-workspace-hack", @@ -7686,7 +7794,7 @@ dependencies = [ "futures-util", "hostname", "http_server_common", - "hyper", + "hyper 0.14.27", "lazy_static", "limitation", "log", diff --git a/crates/vendor/newrelic-telemetry-sdk-rust/Cargo.toml b/crates/vendor/newrelic-telemetry-sdk-rust/Cargo.toml index 088a3cf568..cf1336f3f3 100644 --- a/crates/vendor/newrelic-telemetry-sdk-rust/Cargo.toml +++ b/crates/vendor/newrelic-telemetry-sdk-rust/Cargo.toml @@ -16,7 +16,7 @@ serde = { version = "1.0.57", features = ["derive"] } serde_json = "1.0.108" hyper = { version = "0.14", features = ["http1"], optional = true } -hyper-tls = { version = "0.5.0", optional = true } +hyper-tls = { version = "0.6.0", optional = true } flate2 = { version = "1.0.16", optional = true } futures = { version = "0.3.1", optional = true } tokio = { version = "1.1.0", features = ["macros"], optional = true } From d3be9a3a6b8d258d48557b1b4198e52634aedf9e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Dec 2023 22:09:11 +0000 Subject: [PATCH 010/124] Bump tokio from 0.1.22 to 1.34.0 Bumps [tokio](https://github.com/tokio-rs/tokio) from 0.1.22 to 1.34.0. - [Release notes](https://github.com/tokio-rs/tokio/releases) - [Commits](https://github.com/tokio-rs/tokio/compare/tokio-0.1.22...tokio-1.34.0) --- updated-dependencies: - dependency-name: tokio dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- Cargo.lock | 233 ++++-------------- crates/cli/dev_database_seed/Cargo.toml | 2 +- crates/cli/dev_upload_media_file/Cargo.toml | 2 +- crates/cli/elasticsearch-cli/Cargo.toml | 2 +- crates/cli/scrape_test/Cargo.toml | 2 +- .../lib/api_clients/cloud_storage/Cargo.toml | 2 +- crates/lib/mysql_queries/Cargo.toml | 2 +- crates/service/job/analytics_job/Cargo.toml | 2 +- crates/service/job/download_job/Cargo.toml | 2 +- .../service/job/email_sender_job/Cargo.toml | 2 +- crates/service/job/inference_job/Cargo.toml | 2 +- .../service/job/tts_download_job/Cargo.toml | 2 +- .../service/job/tts_inference_job/Cargo.toml | 2 +- .../service/job/w2l_download_job/Cargo.toml | 2 +- .../service/job/w2l_inference_job/Cargo.toml | 2 +- .../other/twitch_pubsub_subscriber/Cargo.toml | 2 +- crates/service/plugins/billing/Cargo.toml | 2 +- crates/service/web/dummy_service/Cargo.toml | 2 +- crates/service/web/storyteller_web/Cargo.toml | 2 +- .../service/web/websocket_gateway/Cargo.toml | 2 +- crates/vendor/limitation/Cargo.toml | 2 +- .../newrelic-telemetry-sdk-rust/Cargo.toml | 4 +- 22 files changed, 71 insertions(+), 206 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1aaf8d3a68..67129df838 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,7 +23,7 @@ dependencies = [ "parking_lot 0.12.1", "pin-project-lite", "smallvec 1.11.2", - "tokio 1.34.0", + "tokio", "tokio-util", ] @@ -39,7 +39,7 @@ dependencies = [ "futures-sink", "memchr", "pin-project-lite", - "tokio 1.34.0", + "tokio", "tokio-util", "tracing", ] @@ -115,7 +115,7 @@ dependencies = [ "rand 0.8.5", "sha1 0.10.6", "smallvec 1.11.2", - "tokio 1.34.0", + "tokio", "tokio-util", "tracing", "zstd 0.12.4", @@ -153,7 +153,7 @@ dependencies = [ "serde_json", "serde_plain", "tempfile", - "tokio 1.34.0", + "tokio", ] [[package]] @@ -190,7 +190,7 @@ checksum = "28f32d40287d3f402ae0028a9d54bef51af15c8769492826a69d28f81893151d" dependencies = [ "actix-macros", "futures-core", - "tokio 1.34.0", + "tokio", ] [[package]] @@ -206,7 +206,7 @@ dependencies = [ "futures-util", "mio 0.8.9", "socket2 0.5.5", - "tokio 1.34.0", + "tokio", "tracing", ] @@ -285,7 +285,7 @@ dependencies = [ "bytestring", "futures-core", "pin-project-lite", - "tokio 1.34.0", + "tokio", "tokio-util", ] @@ -465,7 +465,7 @@ dependencies = [ "serde_json", "sqlx", "tokens", - "tokio 1.34.0", + "tokio", ] [[package]] @@ -600,7 +600,7 @@ dependencies = [ "futures-core", "memchr", "pin-project-lite", - "tokio 1.34.0", + "tokio", ] [[package]] @@ -624,7 +624,7 @@ dependencies = [ "smart-default", "smol_str", "thiserror", - "tokio 1.34.0", + "tokio", ] [[package]] @@ -810,7 +810,7 @@ dependencies = [ "serde_derive", "serde_json", "sqlx", - "tokio 1.34.0", + "tokio", "toml", "url_config", ] @@ -1162,7 +1162,7 @@ dependencies = [ "log", "my-workspace-hack", "rust-s3", - "tokio 1.34.0", + "tokio", ] [[package]] @@ -1218,7 +1218,7 @@ dependencies = [ "futures-core", "memchr", "pin-project-lite", - "tokio 1.34.0", + "tokio", "tokio-util", ] @@ -1386,17 +1386,6 @@ dependencies = [ "crossbeam-utils 0.8.16", ] -[[package]] -name = "crossbeam-deque" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20ff29ded3204c5106278a81a38f4b482636ed4fa1e6cfbeef193291beb29ed" -dependencies = [ - "crossbeam-epoch 0.8.2", - "crossbeam-utils 0.7.2", - "maybe-uninit", -] - [[package]] name = "crossbeam-deque" version = "0.8.3" @@ -1404,25 +1393,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" dependencies = [ "cfg-if 1.0.0", - "crossbeam-epoch 0.9.15", + "crossbeam-epoch", "crossbeam-utils 0.8.16", ] -[[package]] -name = "crossbeam-epoch" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" -dependencies = [ - "autocfg", - "cfg-if 0.1.10", - "crossbeam-utils 0.7.2", - "lazy_static", - "maybe-uninit", - "memoffset 0.5.6", - "scopeguard", -] - [[package]] name = "crossbeam-epoch" version = "0.9.15" @@ -1436,17 +1410,6 @@ dependencies = [ "scopeguard", ] -[[package]] -name = "crossbeam-queue" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" -dependencies = [ - "cfg-if 0.1.10", - "crossbeam-utils 0.7.2", - "maybe-uninit", -] - [[package]] name = "crossbeam-queue" version = "0.3.8" @@ -1791,7 +1754,7 @@ dependencies = [ "sqlx", "storyteller_root", "tokens", - "tokio 1.34.0", + "tokio", ] [[package]] @@ -1812,7 +1775,7 @@ dependencies = [ "mysql_queries", "sqlx", "tokens", - "tokio 1.34.0", + "tokio", ] [[package]] @@ -1976,7 +1939,7 @@ dependencies = [ "subprocess", "subprocess_common", "tempdir", - "tokio 1.34.0", + "tokio", "zip", ] @@ -2022,7 +1985,7 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "tokio 1.34.0", + "tokio", ] [[package]] @@ -2099,7 +2062,7 @@ dependencies = [ "storyteller_root", "strum", "tokens", - "tokio 1.34.0", + "tokio", ] [[package]] @@ -2174,7 +2137,7 @@ dependencies = [ "tempdir", "testing", "tokens", - "tokio 1.34.0", + "tokio", "tts_common", ] @@ -2639,7 +2602,7 @@ dependencies = [ "http", "indexmap", "slab", - "tokio 1.34.0", + "tokio", "tokio-util", "tracing", ] @@ -2894,7 +2857,7 @@ dependencies = [ "itoa 1.0.9", "pin-project-lite", "socket2 0.4.10", - "tokio 1.34.0", + "tokio", "tower-service", "tracing", "want", @@ -2909,7 +2872,7 @@ dependencies = [ "bytes 1.5.0", "hyper", "native-tls", - "tokio 1.34.0", + "tokio", "tokio-native-tls", ] @@ -3079,7 +3042,7 @@ dependencies = [ "subprocess_common", "tempdir", "tokens", - "tokio 1.34.0", + "tokio", "tts_common", ] @@ -3288,7 +3251,7 @@ dependencies = [ "once_cell", "quoted_printable", "socket2 0.5.5", - "tokio 1.34.0", + "tokio", "url 2.5.0", ] @@ -3353,7 +3316,7 @@ dependencies = [ "my-workspace-hack", "redis 0.13.0", "time 0.1.45", - "tokio 0.1.22", + "tokio", "version-sync", ] @@ -3556,15 +3519,6 @@ version = "2.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" -[[package]] -name = "memoffset" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa" -dependencies = [ - "autocfg", -] - [[package]] name = "memoffset" version = "0.7.1" @@ -3797,7 +3751,7 @@ dependencies = [ "syn 2.0.39", "time 0.3.30", "time-macros", - "tokio 1.34.0", + "tokio", "tokio-stream", "tracing", "twitch_oauth2", @@ -3834,7 +3788,7 @@ dependencies = [ "serial_test", "sqlx", "tokens", - "tokio 1.34.0", + "tokio", "toml", ] @@ -3904,7 +3858,7 @@ dependencies = [ "rand 0.8.5", "serde", "serde_json", - "tokio 1.34.0", + "tokio", "uuid 0.8.2", ] @@ -4733,7 +4687,7 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" dependencies = [ - "crossbeam-deque 0.8.3", + "crossbeam-deque", "crossbeam-utils 0.8.16", ] @@ -4798,7 +4752,7 @@ dependencies = [ "pin-project-lite", "ryu", "sha1 0.6.1", - "tokio 1.34.0", + "tokio", "tokio-util", "url 2.5.0", ] @@ -4921,7 +4875,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "system-configuration", - "tokio 1.34.0", + "tokio", "tokio-native-tls", "tokio-util", "tower-service", @@ -5079,7 +5033,7 @@ dependencies = [ "sha2 0.10.8", "thiserror", "time 0.3.30", - "tokio 1.34.0", + "tokio", "tokio-stream", "url 2.5.0", ] @@ -5251,7 +5205,7 @@ dependencies = [ "clap 2.34.0", "errors", "my-workspace-hack", - "tokio 1.34.0", + "tokio", "web_scrapers", ] @@ -5767,7 +5721,7 @@ dependencies = [ "bytes 1.5.0", "chrono", "crc", - "crossbeam-queue 0.3.8", + "crossbeam-queue", "dotenvy", "either", "event-listener", @@ -5793,7 +5747,7 @@ dependencies = [ "smallvec 1.11.2", "sqlformat", "thiserror", - "tokio 1.34.0", + "tokio", "tokio-stream", "tracing", "url 2.5.0", @@ -5836,7 +5790,7 @@ dependencies = [ "sqlx-sqlite", "syn 1.0.109", "tempfile", - "tokio 1.34.0", + "tokio", "url 2.5.0", ] @@ -6066,7 +6020,7 @@ dependencies = [ "symphonia", "time 0.3.30", "tokens", - "tokio 1.34.0", + "tokio", "toml", "tts_common", "twitch_common", @@ -6583,30 +6537,6 @@ dependencies = [ "utoipa", ] -[[package]] -name = "tokio" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6" -dependencies = [ - "bytes 0.4.12", - "futures 0.1.31", - "mio 0.6.23", - "num_cpus", - "tokio-codec", - "tokio-current-thread", - "tokio-executor", - "tokio-fs", - "tokio-io", - "tokio-reactor", - "tokio-sync", - "tokio-tcp", - "tokio-threadpool", - "tokio-timer", - "tokio-udp", - "tokio-uds", -] - [[package]] name = "tokio" version = "1.34.0" @@ -6637,16 +6567,6 @@ dependencies = [ "tokio-io", ] -[[package]] -name = "tokio-current-thread" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1de0e32a83f131e002238d7ccde18211c0a5397f60cbfffcb112868c2e0e20e" -dependencies = [ - "futures 0.1.31", - "tokio-executor", -] - [[package]] name = "tokio-executor" version = "0.1.10" @@ -6657,17 +6577,6 @@ dependencies = [ "futures 0.1.31", ] -[[package]] -name = "tokio-fs" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "297a1206e0ca6302a0eed35b700d292b275256f596e2f3fea7729d5e629b6ff4" -dependencies = [ - "futures 0.1.31", - "tokio-io", - "tokio-threadpool", -] - [[package]] name = "tokio-io" version = "0.1.13" @@ -6697,7 +6606,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" dependencies = [ "native-tls", - "tokio 1.34.0", + "tokio", ] [[package]] @@ -6726,7 +6635,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" dependencies = [ "rustls 0.19.1", - "tokio 1.34.0", + "tokio", "webpki", ] @@ -6738,7 +6647,7 @@ checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" dependencies = [ "futures-core", "pin-project-lite", - "tokio 1.34.0", + "tokio", ] [[package]] @@ -6765,35 +6674,6 @@ dependencies = [ "tokio-reactor", ] -[[package]] -name = "tokio-threadpool" -version = "0.1.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df720b6581784c118f0eb4310796b12b1d242a7eb95f716a8367855325c25f89" -dependencies = [ - "crossbeam-deque 0.7.4", - "crossbeam-queue 0.2.3", - "crossbeam-utils 0.7.2", - "futures 0.1.31", - "lazy_static", - "log", - "num_cpus", - "slab", - "tokio-executor", -] - -[[package]] -name = "tokio-timer" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93044f2d313c95ff1cb7809ce9a7a05735b012288a888b62d4434fd58c94f296" -dependencies = [ - "crossbeam-utils 0.7.2", - "futures 0.1.31", - "slab", - "tokio-executor", -] - [[package]] name = "tokio-tungstenite" version = "0.15.0" @@ -6804,28 +6684,13 @@ dependencies = [ "log", "pin-project", "rustls 0.19.1", - "tokio 1.34.0", + "tokio", "tokio-rustls", "tungstenite", "webpki", "webpki-roots 0.21.1", ] -[[package]] -name = "tokio-udp" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2a0b10e610b39c38b031a2fcab08e4b82f16ece36504988dcbd81dbba650d82" -dependencies = [ - "bytes 0.4.12", - "futures 0.1.31", - "log", - "mio 0.6.23", - "tokio-codec", - "tokio-io", - "tokio-reactor", -] - [[package]] name = "tokio-uds" version = "0.2.7" @@ -6854,7 +6719,7 @@ dependencies = [ "futures-core", "futures-sink", "pin-project-lite", - "tokio 1.34.0", + "tokio", "tracing", ] @@ -6939,7 +6804,7 @@ dependencies = [ "sqlx", "subprocess", "tempdir", - "tokio 1.34.0", + "tokio", ] [[package]] @@ -6973,7 +6838,7 @@ dependencies = [ "sqlx", "subprocess", "tempdir", - "tokio 1.34.0", + "tokio", "tts_common", ] @@ -7054,7 +6919,7 @@ dependencies = [ "sqlx", "time 0.3.30", "tokens", - "tokio 1.34.0", + "tokio", "tokio-tungstenite", "toml", "tts_common", @@ -7449,7 +7314,7 @@ dependencies = [ "sqlx", "subprocess", "tempdir", - "tokio 1.34.0", + "tokio", ] [[package]] @@ -7478,7 +7343,7 @@ dependencies = [ "sqlx", "subprocess", "tempdir", - "tokio 1.34.0", + "tokio", ] [[package]] @@ -7707,7 +7572,7 @@ dependencies = [ "sha2 0.9.9", "sqlx", "time 0.3.30", - "tokio 1.34.0", + "tokio", "toml", "twitch_api2", "twitch_common", diff --git a/crates/cli/dev_database_seed/Cargo.toml b/crates/cli/dev_database_seed/Cargo.toml index ae63bd60b6..a771241cf5 100644 --- a/crates/cli/dev_database_seed/Cargo.toml +++ b/crates/cli/dev_database_seed/Cargo.toml @@ -37,7 +37,7 @@ clap = "2.34.0" # TODO: This is really out of date, but has conflicts when updat # Runtime # NB: We switched to Tokio from `async-std` for broader ecosystem support. -tokio = { version = "1.6.0", features = ["macros"] } +tokio = { version = "1.34.0", features = ["macros"] } sqlx = { version = "0.7.2", features = [ "mysql", "runtime-tokio", "tls-rustls", "chrono" ] } diff --git a/crates/cli/dev_upload_media_file/Cargo.toml b/crates/cli/dev_upload_media_file/Cargo.toml index ff572d4512..47d58a89c0 100644 --- a/crates/cli/dev_upload_media_file/Cargo.toml +++ b/crates/cli/dev_upload_media_file/Cargo.toml @@ -34,7 +34,7 @@ log = "0.4.14" # Runtime # NB: We switched to Tokio from `async-std` for broader ecosystem support. -tokio = { version = "1.6.0", features = ["macros"] } +tokio = { version = "1.34.0", features = ["macros"] } sqlx = { version = "0.7.2", features = [ "mysql", "runtime-tokio", "tls-rustls", "chrono" ] } diff --git a/crates/cli/elasticsearch-cli/Cargo.toml b/crates/cli/elasticsearch-cli/Cargo.toml index c8f0841c69..7361ad74b6 100644 --- a/crates/cli/elasticsearch-cli/Cargo.toml +++ b/crates/cli/elasticsearch-cli/Cargo.toml @@ -34,7 +34,7 @@ strum = { version = "0.25", features = ["derive"] } # Runtime # NB: We switched to Tokio from `async-std` for broader ecosystem support. -tokio = { version = "1.6.0", features = ["macros"] } +tokio = { version = "1.34.0", features = ["macros"] } sqlx = { version = "0.7.2", features = [ "mysql", "runtime-tokio", "tls-rustls", "chrono" ] } diff --git a/crates/cli/scrape_test/Cargo.toml b/crates/cli/scrape_test/Cargo.toml index d286897c20..36284d1f33 100644 --- a/crates/cli/scrape_test/Cargo.toml +++ b/crates/cli/scrape_test/Cargo.toml @@ -23,4 +23,4 @@ my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" } # External clap = "2.34.0" # TODO: This is really out of date, but has conflicts when updated -tokio = { version = "1.6.0", features = ["macros"] } +tokio = { version = "1.34.0", features = ["macros"] } diff --git a/crates/lib/api_clients/cloud_storage/Cargo.toml b/crates/lib/api_clients/cloud_storage/Cargo.toml index 3d4c2d3f77..2cd5d20198 100644 --- a/crates/lib/api_clients/cloud_storage/Cargo.toml +++ b/crates/lib/api_clients/cloud_storage/Cargo.toml @@ -30,4 +30,4 @@ rust-s3 = { version = "0.33.0" } # Runtime # NB: We switched to Tokio from `async-std` for broader ecosystem support. -tokio = { version = "1.6.0", features = ["macros"] } +tokio = { version = "1.34.0", features = ["macros"] } diff --git a/crates/lib/mysql_queries/Cargo.toml b/crates/lib/mysql_queries/Cargo.toml index 335aab10f3..228c472322 100644 --- a/crates/lib/mysql_queries/Cargo.toml +++ b/crates/lib/mysql_queries/Cargo.toml @@ -43,7 +43,7 @@ serde_json = "1.0.108" toml = "0.5.8" serial_test = "2.0.0" -tokio = { version = "1.6.0", features = ["full"] } +tokio = { version = "1.34.0", features = ["full"] } rand = "0.8" sqlx = { version = "0.7.2", features = [ "mysql", "runtime-tokio", "tls-rustls", "chrono" ] } diff --git a/crates/service/job/analytics_job/Cargo.toml b/crates/service/job/analytics_job/Cargo.toml index 59f30971d9..ed1487b8a3 100644 --- a/crates/service/job/analytics_job/Cargo.toml +++ b/crates/service/job/analytics_job/Cargo.toml @@ -39,7 +39,7 @@ sqlx = { version = "0.7.2", features = [ "mysql", "runtime-tokio", "tls-rustls", # Runtime # NB: We switched to Tokio from `async-std` for broader ecosystem support. -tokio = { version = "1.6.0", features = ["macros"] } +tokio = { version = "1.34.0", features = ["macros"] } # Serialization serde = "1.0.125" diff --git a/crates/service/job/download_job/Cargo.toml b/crates/service/job/download_job/Cargo.toml index 96598161bc..e97068915d 100644 --- a/crates/service/job/download_job/Cargo.toml +++ b/crates/service/job/download_job/Cargo.toml @@ -53,7 +53,7 @@ r2d2_redis = "0.14.0" # Runtime # NB: We switched to Tokio from `async-std` for broader ecosystem support. -tokio = { version = "1.6.0", features = ["macros"] } +tokio = { version = "1.34.0", features = ["macros"] } # NB: Hyper is just for HTTP client use in jobs. I'd use Actix client, but I need tokio runtime # NB: Furthermore, the Tokio runtime is old, so I have to use an older Hyper. diff --git a/crates/service/job/email_sender_job/Cargo.toml b/crates/service/job/email_sender_job/Cargo.toml index de0c02e9d6..f72b7f7fba 100644 --- a/crates/service/job/email_sender_job/Cargo.toml +++ b/crates/service/job/email_sender_job/Cargo.toml @@ -66,7 +66,7 @@ r2d2_redis = "0.14.0" # Runtime # NB: We switched to Tokio from `async-std` for broader ecosystem support. -tokio = { version = "1.6.0", features = ["macros"] } +tokio = { version = "1.34.0", features = ["macros"] } # NB: Hyper is just for HTTP client use in jobs. I'd use Actix client, but I need tokio runtime # NB: Furthermore, the Tokio runtime is old, so I have to use an older Hyper. diff --git a/crates/service/job/inference_job/Cargo.toml b/crates/service/job/inference_job/Cargo.toml index 44b1bb910a..9f8205ca14 100644 --- a/crates/service/job/inference_job/Cargo.toml +++ b/crates/service/job/inference_job/Cargo.toml @@ -62,7 +62,7 @@ r2d2_redis = "0.14.0" # Runtime # NB: We switched to Tokio from `async-std` for broader ecosystem support. -tokio = { version = "1.6.0", features = ["macros"] } +tokio = { version = "1.34.0", features = ["macros"] } # NB: Hyper is just for HTTP client use in jobs. I'd use Actix client, but I need tokio runtime # NB: Furthermore, the Tokio runtime is old, so I have to use an older Hyper. diff --git a/crates/service/job/tts_download_job/Cargo.toml b/crates/service/job/tts_download_job/Cargo.toml index 7506d7f670..07bfd1b465 100644 --- a/crates/service/job/tts_download_job/Cargo.toml +++ b/crates/service/job/tts_download_job/Cargo.toml @@ -45,7 +45,7 @@ r2d2_redis = "0.14.0" # Runtime # NB: We switched to Tokio from `async-std` for broader ecosystem support. -tokio = { version = "1.6.0", features = ["macros"] } +tokio = { version = "1.34.0", features = ["macros"] } # NB: Hyper is just for HTTP client use in jobs. I'd use Actix client, but I need tokio runtime # NB: Furthermore, the Tokio runtime is old, so I have to use an older Hyper. diff --git a/crates/service/job/tts_inference_job/Cargo.toml b/crates/service/job/tts_inference_job/Cargo.toml index 9fbdc2df76..cbfdd24de1 100644 --- a/crates/service/job/tts_inference_job/Cargo.toml +++ b/crates/service/job/tts_inference_job/Cargo.toml @@ -51,7 +51,7 @@ r2d2_redis = "0.14.0" # Runtime # NB: We switched to Tokio from `async-std` for broader ecosystem support. -tokio = { version = "1.6.0", features = ["macros"] } +tokio = { version = "1.34.0", features = ["macros"] } # NB: Hyper is just for HTTP client use in jobs. I'd use Actix client, but I need tokio runtime # NB: Furthermore, the Tokio runtime is old, so I have to use an older Hyper. diff --git a/crates/service/job/w2l_download_job/Cargo.toml b/crates/service/job/w2l_download_job/Cargo.toml index cfdafda722..7819055ed0 100644 --- a/crates/service/job/w2l_download_job/Cargo.toml +++ b/crates/service/job/w2l_download_job/Cargo.toml @@ -45,7 +45,7 @@ r2d2_redis = "0.14.0" # Runtime # NB: We switched to Tokio from `async-std` for broader ecosystem support. -tokio = { version = "1.6.0", features = ["macros"] } +tokio = { version = "1.34.0", features = ["macros"] } # NB: Hyper is just for HTTP client use in jobs. I'd use Actix client, but I need tokio runtime # NB: Furthermore, the Tokio runtime is old, so I have to use an older Hyper. diff --git a/crates/service/job/w2l_inference_job/Cargo.toml b/crates/service/job/w2l_inference_job/Cargo.toml index 34db170d30..ac801c96bd 100644 --- a/crates/service/job/w2l_inference_job/Cargo.toml +++ b/crates/service/job/w2l_inference_job/Cargo.toml @@ -43,7 +43,7 @@ r2d2_redis = "0.14.0" # Runtime # NB: We switched to Tokio from `async-std` for broader ecosystem support. -tokio = { version = "1.6.0", features = ["macros"] } +tokio = { version = "1.34.0", features = ["macros"] } # NB: Hyper is just for HTTP client use in jobs. I'd use Actix client, but I need tokio runtime # NB: Furthermore, the Tokio runtime is old, so I have to use an older Hyper. diff --git a/crates/service/other/twitch_pubsub_subscriber/Cargo.toml b/crates/service/other/twitch_pubsub_subscriber/Cargo.toml index 1fda2a5a73..58a1486caf 100644 --- a/crates/service/other/twitch_pubsub_subscriber/Cargo.toml +++ b/crates/service/other/twitch_pubsub_subscriber/Cargo.toml @@ -43,7 +43,7 @@ uuid = { version = "0.8.2", features = ["v4"] } # Runtime # NB: We switched to Tokio from `async-std` for broader ecosystem support. -tokio = { version = "1.10.0", features = ["rt-multi-thread", "macros", "time"] } +tokio = { version = "1.34.0", features = ["rt-multi-thread", "macros", "time"] } # Futures futures = { version = "0.3.17", features = ["thread-pool"] } # feature for ThreadPool diff --git a/crates/service/plugins/billing/Cargo.toml b/crates/service/plugins/billing/Cargo.toml index 4e123524e9..869eee7790 100644 --- a/crates/service/plugins/billing/Cargo.toml +++ b/crates/service/plugins/billing/Cargo.toml @@ -59,4 +59,4 @@ sqlx = { version = "0.7.2", features = [ "mysql", "runtime-tokio", "tls-rustls", mockall = "0.11.3" # NB: Tokio version matches `async-stripe` transitive dep; features are for testing -tokio = { version = "1.13.0", features = ["rt", "macros"] } +tokio = { version = "1.34.0", features = ["rt", "macros"] } diff --git a/crates/service/web/dummy_service/Cargo.toml b/crates/service/web/dummy_service/Cargo.toml index 671723c73b..4ea1672720 100644 --- a/crates/service/web/dummy_service/Cargo.toml +++ b/crates/service/web/dummy_service/Cargo.toml @@ -32,7 +32,7 @@ hostname = "0.3.1" # Runtime # NB: We switched to Tokio from `async-std` for broader ecosystem support. -tokio = { version = "1.6.0", features = ["macros"] } +tokio = { version = "1.34.0", features = ["macros"] } # Futures futures-util = "0.3.29" diff --git a/crates/service/web/storyteller_web/Cargo.toml b/crates/service/web/storyteller_web/Cargo.toml index c57dddc4db..c8d81cef9a 100644 --- a/crates/service/web/storyteller_web/Cargo.toml +++ b/crates/service/web/storyteller_web/Cargo.toml @@ -95,7 +95,7 @@ native-tls = { version = "0.2.8", features = ["vendored"] } # Runtime # NB: We switched to Tokio from `async-std` for broader ecosystem support. -tokio = { version = "1.6.0", features = ["macros"] } +tokio = { version = "1.34.0", features = ["macros"] } # Futures futures = { version = "0.3.17", features = ["thread-pool"] } # feature for ThreadPool diff --git a/crates/service/web/websocket_gateway/Cargo.toml b/crates/service/web/websocket_gateway/Cargo.toml index f492098015..20c89b006b 100644 --- a/crates/service/web/websocket_gateway/Cargo.toml +++ b/crates/service/web/websocket_gateway/Cargo.toml @@ -43,7 +43,7 @@ uuid = { version = "0.8.2", features = ["v4"] } # Runtime # NB: We switched to Tokio from `async-std` for broader ecosystem support. -tokio = { version = "1.10.0", features = ["rt-multi-thread", "macros", "time"] } +tokio = { version = "1.34.0", features = ["rt-multi-thread", "macros", "time"] } # Futures futures = { version = "0.3.17", features = ["thread-pool"] } # feature for ThreadPool diff --git a/crates/vendor/limitation/Cargo.toml b/crates/vendor/limitation/Cargo.toml index 7c4015b643..51f1626635 100644 --- a/crates/vendor/limitation/Cargo.toml +++ b/crates/vendor/limitation/Cargo.toml @@ -27,5 +27,5 @@ time = "0.1.42" my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" } [dev-dependencies] -tokio = "0.1.22" +tokio = "1.34.0" version-sync = "0.8.1" diff --git a/crates/vendor/newrelic-telemetry-sdk-rust/Cargo.toml b/crates/vendor/newrelic-telemetry-sdk-rust/Cargo.toml index 088a3cf568..df26faf565 100644 --- a/crates/vendor/newrelic-telemetry-sdk-rust/Cargo.toml +++ b/crates/vendor/newrelic-telemetry-sdk-rust/Cargo.toml @@ -19,7 +19,7 @@ hyper = { version = "0.14", features = ["http1"], optional = true } hyper-tls = { version = "0.5.0", optional = true } flate2 = { version = "1.0.16", optional = true } futures = { version = "0.3.1", optional = true } -tokio = { version = "1.1.0", features = ["macros"], optional = true } +tokio = { version = "1.34.0", features = ["macros"], optional = true } uuid = { version = "0.8.1", features = ["v4"] } # Workspace hack (faster compile times) @@ -30,4 +30,4 @@ rand = "0.8.5" env_logger = "0.10.1" futures = { version = "0.3.1" } hyper = { version = "0.14", features = ["http1", "server"] } -tokio = { version = "1.1.0", features = ["macros", "rt-multi-thread"] } +tokio = { version = "1.34.0", features = ["macros", "rt-multi-thread"] } From 1cde23c08087ceecedfa4b9840e896ab4298dd27 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Mon, 11 Dec 2023 20:38:50 -0500 Subject: [PATCH 011/124] Seed media files --- ...5c07196ab520cd8c63d30689b6021fa4b4ec1.json | 12 - ...106ac6bea906979c89355f805abb9650a7588.json | 12 + crates/cli/dev_database_seed/src/main.rs | 2 + .../cli/dev_database_seed/src/seeding/mod.rs | 5 +- .../src/seeding/seed_media_files.rs | 210 ++++++++++++++++++ crates/cli/dev_upload_media_file/src/main.rs | 1 + .../insert_media_file_from_cli_tool.rs | 8 +- 7 files changed, 235 insertions(+), 15 deletions(-) delete mode 100644 .sqlx/query-030e26fa7977555cdd04864d9b95c07196ab520cd8c63d30689b6021fa4b4ec1.json create mode 100644 .sqlx/query-8f8b81d54aeabb31a200de98ba3106ac6bea906979c89355f805abb9650a7588.json create mode 100644 crates/cli/dev_database_seed/src/seeding/seed_media_files.rs diff --git a/.sqlx/query-030e26fa7977555cdd04864d9b95c07196ab520cd8c63d30689b6021fa4b4ec1.json b/.sqlx/query-030e26fa7977555cdd04864d9b95c07196ab520cd8c63d30689b6021fa4b4ec1.json deleted file mode 100644 index fb10d9d281..0000000000 --- a/.sqlx/query-030e26fa7977555cdd04864d9b95c07196ab520cd8c63d30689b6021fa4b4ec1.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "MySQL", - "query": "\nINSERT INTO media_files\nSET\n token = ?,\n\n origin_category = ?,\n origin_product_category = ?,\n\n media_type = ?,\n maybe_mime_type = ?,\n file_size_bytes = ?,\n checksum_sha2 = ?,\n\n public_bucket_directory_hash = ?,\n maybe_public_bucket_prefix = ?,\n maybe_public_bucket_extension = ?,\n\n maybe_creator_user_token = ?,\n creator_ip_address = ?,\n\n creator_set_visibility = ?\n ", - "describe": { - "columns": [], - "parameters": { - "Right": 13 - }, - "nullable": [] - }, - "hash": "030e26fa7977555cdd04864d9b95c07196ab520cd8c63d30689b6021fa4b4ec1" -} diff --git a/.sqlx/query-8f8b81d54aeabb31a200de98ba3106ac6bea906979c89355f805abb9650a7588.json b/.sqlx/query-8f8b81d54aeabb31a200de98ba3106ac6bea906979c89355f805abb9650a7588.json new file mode 100644 index 0000000000..6a0e91bef8 --- /dev/null +++ b/.sqlx/query-8f8b81d54aeabb31a200de98ba3106ac6bea906979c89355f805abb9650a7588.json @@ -0,0 +1,12 @@ +{ + "db_name": "MySQL", + "query": "\nINSERT INTO media_files\nSET\n token = ?,\n\n origin_category = ?,\n origin_product_category = ?,\n\n media_type = ?,\n maybe_mime_type = ?,\n file_size_bytes = ?,\n checksum_sha2 = ?,\n\n maybe_origin_filename = ?,\n\n public_bucket_directory_hash = ?,\n maybe_public_bucket_prefix = ?,\n maybe_public_bucket_extension = ?,\n\n maybe_creator_user_token = ?,\n creator_ip_address = ?,\n\n creator_set_visibility = ?\n ", + "describe": { + "columns": [], + "parameters": { + "Right": 14 + }, + "nullable": [] + }, + "hash": "8f8b81d54aeabb31a200de98ba3106ac6bea906979c89355f805abb9650a7588" +} diff --git a/crates/cli/dev_database_seed/src/main.rs b/crates/cli/dev_database_seed/src/main.rs index 917a8622a0..558478772e 100644 --- a/crates/cli/dev_database_seed/src/main.rs +++ b/crates/cli/dev_database_seed/src/main.rs @@ -8,6 +8,7 @@ use errors::AnyhowResult; use crate::bucket_clients::get_bucket_clients; use crate::cli_args::parse_cli_args; use crate::seeding::model_weights::seed_weights; +use crate::seeding::seed_media_files::seed_media_files; use crate::seeding::tts_tacotron2::seed_tts_tacotron2; use crate::seeding::users::seed_user_accounts; use crate::seeding::voice_conversion::seed_voice_conversion; @@ -52,6 +53,7 @@ pub async fn main() -> AnyhowResult<()> { } seed_user_accounts(&pool).await?; + seed_media_files(&pool, maybe_bucket_clients.as_ref()).await?; seed_zero_shot_tts(&pool, maybe_bucket_clients.as_ref()).await?; seed_voice_conversion(&pool).await?; diff --git a/crates/cli/dev_database_seed/src/seeding/mod.rs b/crates/cli/dev_database_seed/src/seeding/mod.rs index cb462d17c9..c1100805b6 100644 --- a/crates/cli/dev_database_seed/src/seeding/mod.rs +++ b/crates/cli/dev_database_seed/src/seeding/mod.rs @@ -1,5 +1,6 @@ +pub mod model_weights; +pub mod seed_media_files; pub mod tts_tacotron2; pub mod users; pub mod voice_conversion; -pub mod zero_shot_tts; -pub mod model_weights; \ No newline at end of file +pub mod zero_shot_tts; \ No newline at end of file diff --git a/crates/cli/dev_database_seed/src/seeding/seed_media_files.rs b/crates/cli/dev_database_seed/src/seeding/seed_media_files.rs new file mode 100644 index 0000000000..5bca8981e2 --- /dev/null +++ b/crates/cli/dev_database_seed/src/seeding/seed_media_files.rs @@ -0,0 +1,210 @@ +use std::path::Path; + +use log::{info, warn}; +use sqlx::{MySql, Pool}; + +use buckets::public::media_files::original_file::MediaFileBucketPath; +use enums::by_table::media_files::media_file_type::MediaFileType; +use enums::common::visibility::Visibility; +use errors::AnyhowResult; +use filesys::file_read_bytes::file_read_bytes; +use filesys::file_size::file_size; +use filesys::path_to_string::path_to_string; +use hashing::sha256::sha256_hash_file::sha256_hash_file; +use mimetypes::mimetype_for_bytes::get_mimetype_for_bytes; +use mimetypes::mimetype_for_file::get_mimetype_for_file; +use mysql_queries::queries::media_files::get_media_file::get_media_file; +use mysql_queries::queries::media_files::insert_media_file_from_cli_tool::{insert_media_file_from_cli_tool, InsertArgs}; +use storyteller_root::get_seed_tool_data_root; +use tokens::tokens::media_files::MediaFileToken; +use tokens::tokens::users::UserToken; + +use crate::bucket_clients::BucketClients; +use crate::seeding::users::HANASHI_USER_TOKEN; + +pub async fn seed_media_files(mysql_pool: &Pool, maybe_bucket_clients: Option<&BucketClients>) -> AnyhowResult<()> { + info!("Seeding media files..."); + + // NB: This is idempotent and will only install the media files once. + // Delete the records if you want to re-seed. + let media_files = [ + // Images + (HANASHI_USER_TOKEN, "m_cn5t6ywm9k1ge9qzzxst5krc5tm08m", MediaFileType::Image, "media/images/face-animator-inputs/bill.jpg"), + (HANASHI_USER_TOKEN, "m_nf9xebrr8hd1bxkfy7src5k8nv2dzy", MediaFileType::Image, "media/images/face-animator-inputs/elon.jpg"), + (HANASHI_USER_TOKEN, "m_t17zh2r3ahs485b8m7c9q502cs6jqh", MediaFileType::Image, "media/images/face-animator-inputs/ernest.jpg"), + (HANASHI_USER_TOKEN, "m_vms09sby8tyw742y2s66a4w8f0w278", MediaFileType::Image, "media/images/face-animator-inputs/link.jpg"), + (HANASHI_USER_TOKEN, "m_s1z9krfzrscy92jgq3sxhpx1n4vxvc", MediaFileType::Image, "media/images/face-animator-inputs/ripley.jpg"), + (HANASHI_USER_TOKEN, "m_we7mnzbd76g4yn19dm6m53er0pjvew", MediaFileType::Image, "media/images/face-animator-inputs/san.png"), + (HANASHI_USER_TOKEN, "m_wahwz92nxxfg0x42dw9fdrhwq30yk0", MediaFileType::Image, "media/images/face-animator-inputs/zelda.jpg"), + // Audio + (HANASHI_USER_TOKEN, "m_21jxt406aattq2cna1xtgf5m4mjyyr", MediaFileType::Audio, "media/audio/voice-samples/biden.wav"), + (HANASHI_USER_TOKEN, "m_cxzabpxf88h10rshqraksxbqmhs41h", MediaFileType::Audio, "media/audio/voice-samples/brandon1.wav"), + (HANASHI_USER_TOKEN, "m_sq2vhrrmmbr079afk21543aa2jg53g", MediaFileType::Audio, "media/audio/voice-samples/brandon2.wav"), + (HANASHI_USER_TOKEN, "m_s61a8g3jnddr3xdg3gctsjxxk9jwja", MediaFileType::Audio, "media/audio/voice-samples/elon.wav"), + (HANASHI_USER_TOKEN, "m_e59fh75g76pvebx4qe4r4aymd93q30", MediaFileType::Audio, "media/audio/voice-samples/goku.wav"), + (HANASHI_USER_TOKEN, "m_ttq0ym8ht4v0z87zqz27fhadp0743c", MediaFileType::Audio, "media/audio/voice-samples/hillary.wav"), + (HANASHI_USER_TOKEN, "m_300bv6f141hv553fjf287p5gb76k37", MediaFileType::Audio, "media/audio/voice-samples/mario_impersonator.wav"), + (HANASHI_USER_TOKEN, "m_rd1ey2jem8a37r3vna2h9mht6zevs5", MediaFileType::Audio, "media/audio/voice-samples/rick.wav"), + (HANASHI_USER_TOKEN, "m_8n5epqfvs2vh60khap0s3ezem4epkc", MediaFileType::Audio, "media/audio/voice-samples/trump.wav"), + (HANASHI_USER_TOKEN, "m_g6dpwcpq51e6kvmpbbkdvgxfan9k1k", MediaFileType::Audio, "media/audio/voice-samples/trump_tts.wav"), + ]; + + let seed_tool_data_root = get_seed_tool_data_root(); + + for (user_token, media_file_token, media_file_type, subdirectory_path) in media_files { + let user_token = UserToken::new_from_str(user_token); + let media_file_token = MediaFileToken::new_from_str(media_file_token); + + let mut media_file_path = seed_tool_data_root.clone(); + media_file_path.push(subdirectory_path); + + let result = seed_model( + &mysql_pool, + &media_file_token, + &user_token, + media_file_type, + &media_file_path, + maybe_bucket_clients, + ).await; + + match result { + Ok(_) => info!("Seeded {:?}", media_file_path), + Err(err) => warn!(r#" + Could not seed media file {} , {:?} : {:?} + (No worries: if there's a duplicate key error, we probably already + seeded the media file on a previous invocation!) + "#, media_file_token, subdirectory_path, err), + } + } + + Ok(()) +} + +async fn seed_model( + mysql_pool: &Pool, + media_file_token: &MediaFileToken, + user_token: &UserToken, + media_file_type: MediaFileType, + media_file_path: &Path, + maybe_bucket_clients: Option<&BucketClients>, +) -> AnyhowResult<()> { + info!("Seeding Media file {:?} ...", media_file_path); + + let mut bucket_hash = "NOT_UPLOADED_BY_SEED_TOOL".to_string(); + let mut maybe_bucket_prefix = None; + let mut maybe_bucket_extension = None; + + if media_file_exists(mysql_pool, media_file_token).await? { + info!("Media file already seeded: {:?}", media_file_token); + return Ok(()) + } + + if let Some(bucket_clients) = maybe_bucket_clients { + let bucket_details = seed_file_to_bucket(media_file_path, bucket_clients).await?; + bucket_hash = bucket_details.bucket_hash; + maybe_bucket_prefix = bucket_details.maybe_bucket_prefix; + maybe_bucket_extension = bucket_details.maybe_bucket_extension; + } + + let maybe_mime_type = get_mimetype_for_file(media_file_path)?; + let file_size_bytes = file_size(media_file_path)?; + let sha256_checksum = sha256_hash_file(media_file_path)?; + + let maybe_filename = media_file_path + .file_name() + .map(|name| name.to_str()) + .flatten(); + + insert_media_file_from_cli_tool(InsertArgs { + pool: &mysql_pool, + media_file_type, + maybe_mime_type, + file_size_bytes, + sha256_checksum: &sha256_checksum, + maybe_origin_filename: maybe_filename, + maybe_creator_user_token: Some(user_token), + creator_set_visibility: Visibility::Public, + public_bucket_directory_hash: &bucket_hash, + maybe_public_bucket_prefix: maybe_bucket_prefix.as_deref(), + maybe_public_bucket_extension: maybe_bucket_extension.as_deref(), + }).await?; + + Ok(()) +} + +async fn media_file_exists( + mysql_pool: &Pool, + media_file_token: &MediaFileToken, +) -> AnyhowResult { + + const CAN_SEE_DELETED : bool = true; + + let maybe_file = get_media_file( + &media_file_token, + CAN_SEE_DELETED, + mysql_pool + ).await?; + + Ok(maybe_file.is_some()) +} + +struct BucketDetails { + bucket_hash: String, + maybe_bucket_prefix: Option, + maybe_bucket_extension: Option, +} + +async fn seed_file_to_bucket( + media_file_path: &Path, + bucket_clients: &BucketClients, +) -> AnyhowResult { + + info!("Uploading media file {:?} ...", media_file_path); + + let maybe_bucket_prefix = Some("fakeyou_"); + + let maybe_bucket_extension = media_file_path + .extension() + .map(|extension| extension.to_str()) + .flatten(); + + let bucket_location = MediaFileBucketPath::generate_new(maybe_bucket_prefix, maybe_bucket_extension); + + let bucket_path = path_to_string(bucket_location.to_full_object_pathbuf()); + + info!("Reading media file: {:?}", media_file_path); + + let bytes = file_read_bytes(media_file_path)?; + let mimetype = get_mimetype_for_bytes(&bytes).unwrap_or("application/octet-stream"); + + info!("Uploading media file to bucket path: {:?}", bucket_path); + + let _r = bucket_clients.public.upload_file_with_content_type( + &bucket_path, + bytes.as_ref(), + mimetype + ).await?; + + Ok(BucketDetails { + bucket_hash: bucket_location.get_object_hash().to_string(), + maybe_bucket_prefix: maybe_bucket_prefix.map(|s| s.to_string()), + maybe_bucket_extension: maybe_bucket_extension.map(|s| s.to_string()), + }) +} + +// Temporary "test" to generate random tokens. +// #[cfg(test)] +// mod tests { +// use tokens::tokens::media_files::MediaFileToken; +// +// #[test] +// fn test() { +// // Print some randomly sampled tokens +// for _i in 0..50 { +// let token = MediaFileToken::generate(); +// println!("Token: {}", token); +// } +// // Deliberately fail the test to get the output +// assert_eq!(1, 2); +// } +// } diff --git a/crates/cli/dev_upload_media_file/src/main.rs b/crates/cli/dev_upload_media_file/src/main.rs index 7a72bacf56..694780ffb9 100644 --- a/crates/cli/dev_upload_media_file/src/main.rs +++ b/crates/cli/dev_upload_media_file/src/main.rs @@ -123,6 +123,7 @@ pub async fn main() -> AnyhowResult<()> { maybe_mime_type, file_size_bytes: 0, // TODO sha256_checksum: "", // TODO + maybe_origin_filename: None, maybe_creator_user_token: None, creator_set_visibility, public_bucket_directory_hash: public_upload_path.get_object_hash(), diff --git a/crates/lib/mysql_queries/src/queries/media_files/insert_media_file_from_cli_tool.rs b/crates/lib/mysql_queries/src/queries/media_files/insert_media_file_from_cli_tool.rs index 43a543db7d..fb180eba35 100644 --- a/crates/lib/mysql_queries/src/queries/media_files/insert_media_file_from_cli_tool.rs +++ b/crates/lib/mysql_queries/src/queries/media_files/insert_media_file_from_cli_tool.rs @@ -19,7 +19,9 @@ pub struct InsertArgs<'a> { pub file_size_bytes: u64, pub sha256_checksum: &'a str, - pub maybe_creator_user_token: Option, + pub maybe_origin_filename: Option<&'a str>, + + pub maybe_creator_user_token: Option<&'a UserToken>, pub creator_set_visibility: Visibility, pub public_bucket_directory_hash: &'a str, @@ -58,6 +60,8 @@ SET file_size_bytes = ?, checksum_sha2 = ?, + maybe_origin_filename = ?, + public_bucket_directory_hash = ?, maybe_public_bucket_prefix = ?, maybe_public_bucket_extension = ?, @@ -77,6 +81,8 @@ SET args.file_size_bytes, args.sha256_checksum, + args.maybe_origin_filename, + args.public_bucket_directory_hash, args.maybe_public_bucket_prefix, args.maybe_public_bucket_extension, From 30d6bca9b2456faa8c05963a6437226adde225fb Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Mon, 11 Dec 2023 21:53:31 -0500 Subject: [PATCH 012/124] seed video files + fix idempotency --- .../src/seeding/seed_media_files.rs | 30 ++++++++++++++----- crates/cli/dev_upload_media_file/src/main.rs | 1 + .../src/queries/media_files/get_media_file.rs | 2 +- .../insert_media_file_from_cli_tool.rs | 8 ++++- 4 files changed, 31 insertions(+), 10 deletions(-) diff --git a/crates/cli/dev_database_seed/src/seeding/seed_media_files.rs b/crates/cli/dev_database_seed/src/seeding/seed_media_files.rs index 5bca8981e2..15f8959ef6 100644 --- a/crates/cli/dev_database_seed/src/seeding/seed_media_files.rs +++ b/crates/cli/dev_database_seed/src/seeding/seed_media_files.rs @@ -28,14 +28,6 @@ pub async fn seed_media_files(mysql_pool: &Pool, maybe_bucket_clients: Op // NB: This is idempotent and will only install the media files once. // Delete the records if you want to re-seed. let media_files = [ - // Images - (HANASHI_USER_TOKEN, "m_cn5t6ywm9k1ge9qzzxst5krc5tm08m", MediaFileType::Image, "media/images/face-animator-inputs/bill.jpg"), - (HANASHI_USER_TOKEN, "m_nf9xebrr8hd1bxkfy7src5k8nv2dzy", MediaFileType::Image, "media/images/face-animator-inputs/elon.jpg"), - (HANASHI_USER_TOKEN, "m_t17zh2r3ahs485b8m7c9q502cs6jqh", MediaFileType::Image, "media/images/face-animator-inputs/ernest.jpg"), - (HANASHI_USER_TOKEN, "m_vms09sby8tyw742y2s66a4w8f0w278", MediaFileType::Image, "media/images/face-animator-inputs/link.jpg"), - (HANASHI_USER_TOKEN, "m_s1z9krfzrscy92jgq3sxhpx1n4vxvc", MediaFileType::Image, "media/images/face-animator-inputs/ripley.jpg"), - (HANASHI_USER_TOKEN, "m_we7mnzbd76g4yn19dm6m53er0pjvew", MediaFileType::Image, "media/images/face-animator-inputs/san.png"), - (HANASHI_USER_TOKEN, "m_wahwz92nxxfg0x42dw9fdrhwq30yk0", MediaFileType::Image, "media/images/face-animator-inputs/zelda.jpg"), // Audio (HANASHI_USER_TOKEN, "m_21jxt406aattq2cna1xtgf5m4mjyyr", MediaFileType::Audio, "media/audio/voice-samples/biden.wav"), (HANASHI_USER_TOKEN, "m_cxzabpxf88h10rshqraksxbqmhs41h", MediaFileType::Audio, "media/audio/voice-samples/brandon1.wav"), @@ -47,6 +39,27 @@ pub async fn seed_media_files(mysql_pool: &Pool, maybe_bucket_clients: Op (HANASHI_USER_TOKEN, "m_rd1ey2jem8a37r3vna2h9mht6zevs5", MediaFileType::Audio, "media/audio/voice-samples/rick.wav"), (HANASHI_USER_TOKEN, "m_8n5epqfvs2vh60khap0s3ezem4epkc", MediaFileType::Audio, "media/audio/voice-samples/trump.wav"), (HANASHI_USER_TOKEN, "m_g6dpwcpq51e6kvmpbbkdvgxfan9k1k", MediaFileType::Audio, "media/audio/voice-samples/trump_tts.wav"), + // Images + (HANASHI_USER_TOKEN, "m_cn5t6ywm9k1ge9qzzxst5krc5tm08m", MediaFileType::Image, "media/image/face-animator-inputs/bill.jpg"), + (HANASHI_USER_TOKEN, "m_nf9xebrr8hd1bxkfy7src5k8nv2dzy", MediaFileType::Image, "media/image/face-animator-inputs/elon.jpg"), + (HANASHI_USER_TOKEN, "m_t17zh2r3ahs485b8m7c9q502cs6jqh", MediaFileType::Image, "media/image/face-animator-inputs/ernest.jpg"), + (HANASHI_USER_TOKEN, "m_vms09sby8tyw742y2s66a4w8f0w278", MediaFileType::Image, "media/image/face-animator-inputs/link.jpg"), + (HANASHI_USER_TOKEN, "m_s1z9krfzrscy92jgq3sxhpx1n4vxvc", MediaFileType::Image, "media/image/face-animator-inputs/ripley.jpg"), + (HANASHI_USER_TOKEN, "m_we7mnzbd76g4yn19dm6m53er0pjvew", MediaFileType::Image, "media/image/face-animator-inputs/san.png"), + (HANASHI_USER_TOKEN, "m_wahwz92nxxfg0x42dw9fdrhwq30yk0", MediaFileType::Image, "media/image/face-animator-inputs/zelda.jpg"), + // Video + (HANASHI_USER_TOKEN, "m_gedarcfdkxx3zv8zz2wmwsnc1r8jbp", MediaFileType::Video, "media/video/storyteller-studio-renders/girl-rotating-room.mp4"), + (HANASHI_USER_TOKEN, "m_3s74yyd4jwrjdp17yx1694n29jv5gr", MediaFileType::Video, "media/video/storyteller-studio-renders/hanashi-run.mp4"), + (HANASHI_USER_TOKEN, "m_p6d64gm1wawz25bmdahfded3366b9f", MediaFileType::Video, "media/video/storyteller-studio-renders/mocap-kiss.mp4"), + (HANASHI_USER_TOKEN, "m_szp2c77z6je965k44vc22xn9432a88", MediaFileType::Video, "media/video/storyteller-studio-renders/rotating-mocap-girl.mp4"), + (HANASHI_USER_TOKEN, "m_mdwspz81zymw9hvmb1d3jm830t25xe", MediaFileType::Video, "media/video/storyteller-studio-renders/rotating-mocap-m.mp4"), + (HANASHI_USER_TOKEN, "m_prcs6xkm8phs5y4a2dfwemwjy6n6z3", MediaFileType::Video, "media/video/storyteller-studio-renders/rotating-run-girl.mp4"), + (HANASHI_USER_TOKEN, "m_5j889dzw08vn9pbrscx1sncff43ekp", MediaFileType::Video, "media/video/storyteller-studio-renders/rotating-run-jww.mp4"), + (HANASHI_USER_TOKEN, "m_fwm2w6wbssez274ayz6x8ta0h1a9qp", MediaFileType::Video, "media/video/storyteller-studio-renders/rotating-run-pascal.mp4"), + (HANASHI_USER_TOKEN, "m_yqqkrt2srep6a35xg78114jn9epwg1", MediaFileType::Video, "media/video/storyteller-studio-renders/rotating-run-pop.mp4"), + (HANASHI_USER_TOKEN, "m_m4r043kez14pm6vaamsecpz8fafh7g", MediaFileType::Video, "media/video/video-style-transfer/man-explaining.mp4"), + (HANASHI_USER_TOKEN, "m_81gq3hygqvrahg6ncxbtcpjap4f9nv", MediaFileType::Video, "media/video/video-style-transfer/woman-gradient-background.mp4"), + (HANASHI_USER_TOKEN, "m_dp9ykj3yasjx69g2fx2bpd26wwjz0f", MediaFileType::Video, "media/video/video-style-transfer/woman-red-hair.mp4"), ]; let seed_tool_data_root = get_seed_tool_data_root(); @@ -117,6 +130,7 @@ async fn seed_model( insert_media_file_from_cli_tool(InsertArgs { pool: &mysql_pool, + maybe_use_apriori_media_token: Some(media_file_token), media_file_type, maybe_mime_type, file_size_bytes, diff --git a/crates/cli/dev_upload_media_file/src/main.rs b/crates/cli/dev_upload_media_file/src/main.rs index 694780ffb9..4112093b85 100644 --- a/crates/cli/dev_upload_media_file/src/main.rs +++ b/crates/cli/dev_upload_media_file/src/main.rs @@ -119,6 +119,7 @@ pub async fn main() -> AnyhowResult<()> { let (media_file_token, _id) = insert_media_file_from_cli_tool(InsertArgs { pool: &pool, + maybe_use_apriori_media_token: None, media_file_type, maybe_mime_type, file_size_bytes: 0, // TODO diff --git a/crates/lib/mysql_queries/src/queries/media_files/get_media_file.rs b/crates/lib/mysql_queries/src/queries/media_files/get_media_file.rs index ec94000555..8dc215e82f 100644 --- a/crates/lib/mysql_queries/src/queries/media_files/get_media_file.rs +++ b/crates/lib/mysql_queries/src/queries/media_files/get_media_file.rs @@ -13,7 +13,7 @@ use errors::AnyhowResult; use tokens::tokens::media_files::MediaFileToken; use tokens::tokens::users::UserToken; -#[derive(Serialize)] +#[derive(Serialize, Debug)] pub struct MediaFile { pub token: MediaFileToken, diff --git a/crates/lib/mysql_queries/src/queries/media_files/insert_media_file_from_cli_tool.rs b/crates/lib/mysql_queries/src/queries/media_files/insert_media_file_from_cli_tool.rs index fb180eba35..e829ba53fd 100644 --- a/crates/lib/mysql_queries/src/queries/media_files/insert_media_file_from_cli_tool.rs +++ b/crates/lib/mysql_queries/src/queries/media_files/insert_media_file_from_cli_tool.rs @@ -14,6 +14,10 @@ use tokens::tokens::users::UserToken; pub struct InsertArgs<'a> { pub pool: &'a MySqlPool, + /// If supplied, use this media token rather than generating a new one. + /// This is good to support idempotency in development and testing. + pub maybe_use_apriori_media_token: Option<&'a MediaFileToken>, + pub media_file_type: MediaFileType, pub maybe_mime_type: Option<&'a str>, pub file_size_bytes: u64, @@ -35,7 +39,9 @@ pub async fn insert_media_file_from_cli_tool( args: InsertArgs<'_> ) -> AnyhowResult<(MediaFileToken, u64)> { - let media_file_token = MediaFileToken::generate(); + let media_file_token = args.maybe_use_apriori_media_token + .map(|token| token.clone()) + .unwrap_or_else(|| MediaFileToken::generate()); let mut transaction = args.pool.begin().await?; From 795eb7a141851fa63a18c739d5b369309608475d Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Tue, 12 Dec 2023 02:15:06 -0500 Subject: [PATCH 013/124] spacing nit --- .../inference_job/config/inference-job.development.env | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/service/job/inference_job/config/inference-job.development.env b/crates/service/job/inference_job/config/inference-job.development.env index c16128c8d6..a8427bea58 100644 --- a/crates/service/job/inference_job/config/inference-job.development.env +++ b/crates/service/job/inference_job/config/inference-job.development.env @@ -18,11 +18,11 @@ REDIS_FOR_KEEPALIVE_URL="redis://localhost/0" # should rename my folder # abs path to the folder that contains the inference code need to get that container in the repo need basepath? relative to everyones env VALL_E_X_INFERENCE_ROOT_DIRECTORY="%storyteller_ml%/tts/VALL-E-X" -#VALL_E_X_INFERENCE_ROOT_DIRECTORY = "/home/tensor/code/storyteller/storyteller-ml/tts/VALL-E-X" -VALL_E_X_INFERENCE_COMMAND = "python3 main.py" -VALL_E_X_INFERENCE_MAYBE_VENV_COMMAND = "source .venv/bin/activate" +#VALL_E_X_INFERENCE_ROOT_DIRECTORY="/home/tensor/code/storyteller/storyteller-ml/tts/VALL-E-X" +VALL_E_X_INFERENCE_COMMAND="python3 main.py" +VALL_E_X_INFERENCE_MAYBE_VENV_COMMAND="source .venv/bin/activate" -# VALL_E_X_INFERENCE_MAYBE_DOCKER_IMAGE = "" # fill this out for dev? +# VALL_E_X_INFERENCE_MAYBE_DOCKER_IMAGE="" # fill this out for dev? #VALL_E_X_INFERENCE_ROOT_DIRECTORY="%storyteller_ml%/tts/VALL-E-X" #VALL_E_X_INFERENCE_COMMAND="python3 main.py" #VALL_E_X_INFERENCE_MAYBE_VENV_COMMAND="source .env/bin/activate" From 07750fa122614d81f948a2ce655d90c4427259cb Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Tue, 12 Dec 2023 02:55:23 -0500 Subject: [PATCH 014/124] refactor bucket modules --- crates/_types/buckets/src/private/mod.rs | 3 ++- .../zs_voices/bucket_directory.rs} | 4 ++-- .../zs_voices/bucket_file_path.rs} | 15 ++++++--------- .../_types/buckets/src/private/zs_voices/mod.rs | 2 ++ .../{directory.rs => bucket_directory.rs} | 3 +-- .../{original_file.rs => bucket_file_path.rs} | 4 ++-- .../_types/buckets/src/public/media_files/mod.rs | 4 ++-- .../{directory.rs => bucket_directory.rs} | 2 +- .../{original_file.rs => bucket_file_path.rs} | 4 ++-- .../buckets/src/public/media_uploads/mod.rs | 4 ++-- crates/_types/buckets/src/public/mod.rs | 1 - .../{directory.rs => bucket_directory.rs} | 2 +- .../{original_file.rs => bucket_file_path.rs} | 4 ++-- .../src/public/voice_conversion_results/mod.rs | 4 ++-- .../{directory.rs => bucket_directory.rs} | 2 +- .../{original_file.rs => bucket_file_path.rs} | 5 +++-- .../buckets/src/public/weight_uploads/mod.rs | 4 ++-- crates/_types/buckets/src/public/zs_voices/mod.rs | 2 -- .../src/seeding/model_weights.rs | 6 ++---- .../src/seeding/seed_media_files.rs | 2 +- .../src/seeding/zero_shot_tts.rs | 2 +- crates/cli/dev_upload_media_file/src/main.rs | 2 +- .../queries/media_uploads/insert_media_upload.rs | 2 +- .../queries/user_bookmarks/list_user_bookmarks.rs | 5 ++--- .../insert_dataset_sample_and_media_file.rs | 2 +- .../lipsync/sad_talker/download_audio_file.rs | 6 +++--- .../lipsync/sad_talker/download_image_file.rs | 4 ++-- .../job_types/lipsync/sad_talker/process_job.rs | 2 +- .../tacotron2_v2_early_fakeyou/upload_results.rs | 2 +- .../tts/vall_e_x/process_job_create_voice.rs | 6 +++--- .../tts/vall_e_x/process_job_inference_voice.rs | 6 +++--- .../src/job/job_types/vc/rvc_v2/process_job.rs | 4 ++-- .../job/job_types/vc/so_vits_svc/process_job.rs | 4 ++-- .../inference_job/get_inference_job_status.rs | 4 ++-- .../endpoints/media_files/get_media_file.rs | 2 +- .../media_uploads/common/handle_upload.rs | 2 +- .../endpoints/tts/get_tts_inference_job_status.rs | 2 +- .../voice_dataset_samples/upload_zs_sample.rs | 2 +- 38 files changed, 65 insertions(+), 71 deletions(-) rename crates/_types/buckets/src/{public/zs_voices/directory.rs => private/zs_voices/bucket_directory.rs} (96%) rename crates/_types/buckets/src/{public/zs_voices/file.rs => private/zs_voices/bucket_file_path.rs} (88%) create mode 100644 crates/_types/buckets/src/private/zs_voices/mod.rs rename crates/_types/buckets/src/public/media_files/{directory.rs => bucket_directory.rs} (96%) rename crates/_types/buckets/src/public/media_files/{original_file.rs => bucket_file_path.rs} (96%) rename crates/_types/buckets/src/public/media_uploads/{directory.rs => bucket_directory.rs} (96%) rename crates/_types/buckets/src/public/media_uploads/{original_file.rs => bucket_file_path.rs} (94%) rename crates/_types/buckets/src/public/voice_conversion_results/{directory.rs => bucket_directory.rs} (95%) rename crates/_types/buckets/src/public/voice_conversion_results/{original_file.rs => bucket_file_path.rs} (94%) rename crates/_types/buckets/src/public/weight_uploads/{directory.rs => bucket_directory.rs} (96%) rename crates/_types/buckets/src/public/weight_uploads/{original_file.rs => bucket_file_path.rs} (94%) delete mode 100644 crates/_types/buckets/src/public/zs_voices/mod.rs diff --git a/crates/_types/buckets/src/private/mod.rs b/crates/_types/buckets/src/private/mod.rs index 27089e4df1..d3090254af 100644 --- a/crates/_types/buckets/src/private/mod.rs +++ b/crates/_types/buckets/src/private/mod.rs @@ -1 +1,2 @@ -pub mod private_path; \ No newline at end of file +pub mod private_path; +pub mod zs_voices; \ No newline at end of file diff --git a/crates/_types/buckets/src/public/zs_voices/directory.rs b/crates/_types/buckets/src/private/zs_voices/bucket_directory.rs similarity index 96% rename from crates/_types/buckets/src/public/zs_voices/directory.rs rename to crates/_types/buckets/src/private/zs_voices/bucket_directory.rs index 1cfc740769..9d4ecee304 100644 --- a/crates/_types/buckets/src/public/zs_voices/directory.rs +++ b/crates/_types/buckets/src/private/zs_voices/bucket_directory.rs @@ -1,6 +1,6 @@ use crockford::crockford_entropy_lower; -use crate::private::private_path::PrivatePath; +use crate::private::private_path::PrivatePath; use crate::util::hashed_directory_path_long_string::hashed_directory_path_long_string; // TODO: Generate these from a macro. @@ -79,7 +79,7 @@ impl ZeroShotVoiceEmbeddingBucketDirectory { #[cfg(test)] mod tests { - use crate::public::zs_voices::directory::{ModelCategory, ModelType, ZeroShotVoiceEmbeddingBucketDirectory}; + use crate::private::zs_voices::bucket_directory::{ModelCategory, ModelType, ZeroShotVoiceEmbeddingBucketDirectory}; #[test] pub fn generate_new_entropy() { diff --git a/crates/_types/buckets/src/public/zs_voices/file.rs b/crates/_types/buckets/src/private/zs_voices/bucket_file_path.rs similarity index 88% rename from crates/_types/buckets/src/public/zs_voices/file.rs rename to crates/_types/buckets/src/private/zs_voices/bucket_file_path.rs index 6428936c7c..47948912ec 100644 --- a/crates/_types/buckets/src/public/zs_voices/file.rs +++ b/crates/_types/buckets/src/private/zs_voices/bucket_file_path.rs @@ -3,11 +3,10 @@ use std::path::PathBuf; use crockford::crockford_entropy_lower; use crate::private::private_path::PrivatePath; -use crate::public::zs_voices::directory::{ModelCategory, ModelType, ZeroShotVoiceEmbeddingBucketDirectory}; +use crate::private::zs_voices::bucket_directory::{ModelCategory, ModelType, ZeroShotVoiceEmbeddingBucketDirectory}; // TODO: Generate these from a macro. - /// The original user upload file. /// It may have derivative files (down samples, crops, etc.) that live alongside it. #[derive(Clone)] @@ -74,11 +73,9 @@ impl ZeroShotVoiceEmbeddingBucketPath { mod tests { use std::path::PathBuf; - use crate::public::media_files::original_file::MediaFileBucketPath; - mod with_prefix_and_extension { - use crate::public::zs_voices::directory::ModelCategory; - use crate::public::zs_voices::file::{ModelType, ZeroShotVoiceEmbeddingBucketPath}; + use crate::private::zs_voices::bucket_directory::ModelCategory; + use crate::private::zs_voices::bucket_file_path::{ModelType, ZeroShotVoiceEmbeddingBucketPath}; #[test] pub fn generate_new_entropy() { @@ -97,8 +94,8 @@ mod tests { } mod without_prefix_and_extension { - use crate::public::zs_voices::directory::ModelCategory; - use crate::public::zs_voices::file::{ModelType, ZeroShotVoiceEmbeddingBucketPath}; + use crate::private::zs_voices::bucket_directory::ModelCategory; + use crate::private::zs_voices::bucket_file_path::{ModelType, ZeroShotVoiceEmbeddingBucketPath}; use super::*; @@ -135,7 +132,7 @@ mod tests { #[test] pub fn get_object_hash() { let hash = "abcdefghijk"; - let file = MediaFileBucketPath::from_object_hash(hash, None, None); + let file = ZeroShotVoiceEmbeddingBucketPath::from_object_hash(hash, ModelCategory::Tts, ModelType::VallEx, 1); assert_eq!(file.get_object_hash(), hash); } } diff --git a/crates/_types/buckets/src/private/zs_voices/mod.rs b/crates/_types/buckets/src/private/zs_voices/mod.rs new file mode 100644 index 0000000000..29c183a5c6 --- /dev/null +++ b/crates/_types/buckets/src/private/zs_voices/mod.rs @@ -0,0 +1,2 @@ +pub mod bucket_directory; +pub mod bucket_file_path; \ No newline at end of file diff --git a/crates/_types/buckets/src/public/media_files/directory.rs b/crates/_types/buckets/src/public/media_files/bucket_directory.rs similarity index 96% rename from crates/_types/buckets/src/public/media_files/directory.rs rename to crates/_types/buckets/src/public/media_files/bucket_directory.rs index e0083da128..855332bcf3 100644 --- a/crates/_types/buckets/src/public/media_files/directory.rs +++ b/crates/_types/buckets/src/public/media_files/bucket_directory.rs @@ -4,7 +4,6 @@ use crate::public::public_path::PublicPath; use crate::util::hashed_directory_path_long_string::hashed_directory_path_long_string; // TODO: Generate these from a macro. - // TODO: Use a central path registry for quick reference const MEDIA_FILE_DIRECTORY: &str = "/media"; @@ -47,7 +46,7 @@ impl MediaFileBucketDirectory { #[cfg(test)] mod tests { - use crate::public::media_files::directory::MediaFileBucketDirectory; + use crate::public::media_files::bucket_directory::MediaFileBucketDirectory; #[test] pub fn generate_new_entropy() { diff --git a/crates/_types/buckets/src/public/media_files/original_file.rs b/crates/_types/buckets/src/public/media_files/bucket_file_path.rs similarity index 96% rename from crates/_types/buckets/src/public/media_files/original_file.rs rename to crates/_types/buckets/src/public/media_files/bucket_file_path.rs index efd0fd9458..e503819440 100644 --- a/crates/_types/buckets/src/public/media_files/original_file.rs +++ b/crates/_types/buckets/src/public/media_files/bucket_file_path.rs @@ -2,7 +2,7 @@ use std::path::PathBuf; use crockford::crockford_entropy_lower; -use crate::public::media_files::directory::MediaFileBucketDirectory; +use crate::public::media_files::bucket_directory::MediaFileBucketDirectory; use crate::public::public_path::PublicPath; const ORIGINAL_FILE_BASENAME : &str = "file.bin"; @@ -79,7 +79,7 @@ impl MediaFileBucketPath { mod tests { use std::path::PathBuf; - use crate::public::media_files::original_file::MediaFileBucketPath; + use crate::public::media_files::bucket_file_path::MediaFileBucketPath; mod with_prefix_and_extension { use super::*; diff --git a/crates/_types/buckets/src/public/media_files/mod.rs b/crates/_types/buckets/src/public/media_files/mod.rs index 42ede393cf..29c183a5c6 100644 --- a/crates/_types/buckets/src/public/media_files/mod.rs +++ b/crates/_types/buckets/src/public/media_files/mod.rs @@ -1,2 +1,2 @@ -pub mod directory; -pub mod original_file; \ No newline at end of file +pub mod bucket_directory; +pub mod bucket_file_path; \ No newline at end of file diff --git a/crates/_types/buckets/src/public/media_uploads/directory.rs b/crates/_types/buckets/src/public/media_uploads/bucket_directory.rs similarity index 96% rename from crates/_types/buckets/src/public/media_uploads/directory.rs rename to crates/_types/buckets/src/public/media_uploads/bucket_directory.rs index aa4ffc0470..77ff4ca662 100644 --- a/crates/_types/buckets/src/public/media_uploads/directory.rs +++ b/crates/_types/buckets/src/public/media_uploads/bucket_directory.rs @@ -47,7 +47,7 @@ impl MediaUploadDirectory { #[cfg(test)] mod tests { - use crate::public::media_uploads::directory::MediaUploadDirectory; + use crate::public::media_uploads::bucket_directory::MediaUploadDirectory; #[test] pub fn generate_new_entropy() { diff --git a/crates/_types/buckets/src/public/media_uploads/original_file.rs b/crates/_types/buckets/src/public/media_uploads/bucket_file_path.rs similarity index 94% rename from crates/_types/buckets/src/public/media_uploads/original_file.rs rename to crates/_types/buckets/src/public/media_uploads/bucket_file_path.rs index 7f0a40a6b7..6867ff6e5a 100644 --- a/crates/_types/buckets/src/public/media_uploads/original_file.rs +++ b/crates/_types/buckets/src/public/media_uploads/bucket_file_path.rs @@ -2,7 +2,7 @@ use std::path::PathBuf; use crockford::crockford_entropy_lower; -use crate::public::media_uploads::directory::MediaUploadDirectory; +use crate::public::media_uploads::bucket_directory::MediaUploadDirectory; use crate::public::public_path::PublicPath; const ORIGINAL_FILE_BASENAME : &str = "original_upload.bin"; @@ -61,7 +61,7 @@ impl MediaUploadOriginalFilePath { mod tests { use std::path::PathBuf; - use crate::public::media_uploads::original_file::MediaUploadOriginalFilePath; + use crate::public::media_uploads::bucket_file_path::MediaUploadOriginalFilePath; #[test] pub fn generate_new_entropy() { diff --git a/crates/_types/buckets/src/public/media_uploads/mod.rs b/crates/_types/buckets/src/public/media_uploads/mod.rs index 42ede393cf..29c183a5c6 100644 --- a/crates/_types/buckets/src/public/media_uploads/mod.rs +++ b/crates/_types/buckets/src/public/media_uploads/mod.rs @@ -1,2 +1,2 @@ -pub mod directory; -pub mod original_file; \ No newline at end of file +pub mod bucket_directory; +pub mod bucket_file_path; \ No newline at end of file diff --git a/crates/_types/buckets/src/public/mod.rs b/crates/_types/buckets/src/public/mod.rs index dc35c40ed4..fcceb68d9b 100644 --- a/crates/_types/buckets/src/public/mod.rs +++ b/crates/_types/buckets/src/public/mod.rs @@ -2,5 +2,4 @@ pub mod media_files; pub mod media_uploads; pub mod public_path; pub mod voice_conversion_results; -pub mod zs_voices; pub mod weight_uploads; \ No newline at end of file diff --git a/crates/_types/buckets/src/public/voice_conversion_results/directory.rs b/crates/_types/buckets/src/public/voice_conversion_results/bucket_directory.rs similarity index 95% rename from crates/_types/buckets/src/public/voice_conversion_results/directory.rs rename to crates/_types/buckets/src/public/voice_conversion_results/bucket_directory.rs index c853cf2d2f..4f726b2c14 100644 --- a/crates/_types/buckets/src/public/voice_conversion_results/directory.rs +++ b/crates/_types/buckets/src/public/voice_conversion_results/bucket_directory.rs @@ -40,7 +40,7 @@ impl VoiceConversionResultDirectory { #[cfg(test)] mod tests { - use crate::public::voice_conversion_results::directory::VoiceConversionResultDirectory; + use crate::public::voice_conversion_results::bucket_directory::VoiceConversionResultDirectory; #[test] pub fn get_directory_path_str() { diff --git a/crates/_types/buckets/src/public/voice_conversion_results/original_file.rs b/crates/_types/buckets/src/public/voice_conversion_results/bucket_file_path.rs similarity index 94% rename from crates/_types/buckets/src/public/voice_conversion_results/original_file.rs rename to crates/_types/buckets/src/public/voice_conversion_results/bucket_file_path.rs index 9e256e89d2..9163363e49 100644 --- a/crates/_types/buckets/src/public/voice_conversion_results/original_file.rs +++ b/crates/_types/buckets/src/public/voice_conversion_results/bucket_file_path.rs @@ -3,7 +3,7 @@ use std::path::PathBuf; use crockford::crockford_entropy_lower; use crate::public::public_path::PublicPath; -use crate::public::voice_conversion_results::directory::VoiceConversionResultDirectory; +use crate::public::voice_conversion_results::bucket_directory::VoiceConversionResultDirectory; const ORIGINAL_FILE_PREFIX : &str = "fakeyou_"; const ORIGINAL_FILE_SUFFIX : &str = ".wav"; @@ -65,7 +65,7 @@ impl VoiceConversionResultOriginalFilePath { mod tests { use std::path::PathBuf; - use crate::public::voice_conversion_results::original_file::VoiceConversionResultOriginalFilePath; + use crate::public::voice_conversion_results::bucket_file_path::VoiceConversionResultOriginalFilePath; #[test] pub fn generate_new_entropy() { diff --git a/crates/_types/buckets/src/public/voice_conversion_results/mod.rs b/crates/_types/buckets/src/public/voice_conversion_results/mod.rs index 42ede393cf..29c183a5c6 100644 --- a/crates/_types/buckets/src/public/voice_conversion_results/mod.rs +++ b/crates/_types/buckets/src/public/voice_conversion_results/mod.rs @@ -1,2 +1,2 @@ -pub mod directory; -pub mod original_file; \ No newline at end of file +pub mod bucket_directory; +pub mod bucket_file_path; \ No newline at end of file diff --git a/crates/_types/buckets/src/public/weight_uploads/directory.rs b/crates/_types/buckets/src/public/weight_uploads/bucket_directory.rs similarity index 96% rename from crates/_types/buckets/src/public/weight_uploads/directory.rs rename to crates/_types/buckets/src/public/weight_uploads/bucket_directory.rs index fcedda62dd..1f3e016fb1 100644 --- a/crates/_types/buckets/src/public/weight_uploads/directory.rs +++ b/crates/_types/buckets/src/public/weight_uploads/bucket_directory.rs @@ -48,7 +48,7 @@ impl WeightUploadDirectory { #[cfg(test)] mod tests { - use crate::public::weight_uploads::directory::WeightUploadDirectory; + use crate::public::weight_uploads::bucket_directory::WeightUploadDirectory; #[test] pub fn generate_new_entropy() { diff --git a/crates/_types/buckets/src/public/weight_uploads/original_file.rs b/crates/_types/buckets/src/public/weight_uploads/bucket_file_path.rs similarity index 94% rename from crates/_types/buckets/src/public/weight_uploads/original_file.rs rename to crates/_types/buckets/src/public/weight_uploads/bucket_file_path.rs index 42f203f849..69ca626486 100644 --- a/crates/_types/buckets/src/public/weight_uploads/original_file.rs +++ b/crates/_types/buckets/src/public/weight_uploads/bucket_file_path.rs @@ -2,8 +2,8 @@ use std::path::PathBuf; use crockford::crockford_entropy_lower; -use crate::public::weight_uploads::directory::WeightUploadDirectory; use crate::public::public_path::PublicPath; +use crate::public::weight_uploads::bucket_directory::WeightUploadDirectory; const ORIGINAL_FILE_BASENAME : &str = "original_upload.bin"; @@ -56,7 +56,8 @@ impl WeightUploadOriginalFilePath { #[cfg(test)] mod tests { use std::path::PathBuf; - use crate::public::weight_uploads::original_file::WeightUploadOriginalFilePath; + + use crate::public::weight_uploads::bucket_file_path::WeightUploadOriginalFilePath; #[test] pub fn generate_new_entropy() { diff --git a/crates/_types/buckets/src/public/weight_uploads/mod.rs b/crates/_types/buckets/src/public/weight_uploads/mod.rs index 42ede393cf..29c183a5c6 100644 --- a/crates/_types/buckets/src/public/weight_uploads/mod.rs +++ b/crates/_types/buckets/src/public/weight_uploads/mod.rs @@ -1,2 +1,2 @@ -pub mod directory; -pub mod original_file; \ No newline at end of file +pub mod bucket_directory; +pub mod bucket_file_path; \ No newline at end of file diff --git a/crates/_types/buckets/src/public/zs_voices/mod.rs b/crates/_types/buckets/src/public/zs_voices/mod.rs deleted file mode 100644 index a5c0d4bfab..0000000000 --- a/crates/_types/buckets/src/public/zs_voices/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod directory; -pub mod file; \ No newline at end of file diff --git a/crates/cli/dev_database_seed/src/seeding/model_weights.rs b/crates/cli/dev_database_seed/src/seeding/model_weights.rs index e766086a0b..8860d323c7 100644 --- a/crates/cli/dev_database_seed/src/seeding/model_weights.rs +++ b/crates/cli/dev_database_seed/src/seeding/model_weights.rs @@ -16,7 +16,7 @@ use tokens::tokens::users::UserToken; use crate::seeding::users::HANASHI_USERNAME; -pub async fn seed_weights_for_paging( mysql_pool: &Pool,user_token: UserToken) -> AnyhowResult<()> { +pub async fn seed_weights_for_paging(mysql_pool: &Pool, user_token: UserToken) -> AnyhowResult<()> { let sd1_5_markdown_description = r#" # Dragonfruit AI Models Update and Workflow @@ -81,9 +81,7 @@ pub async fn seed_weights_for_paging( mysql_pool: &Pool,user_token: User *Thank you for your continued support and feedback!* "#; -let sd1_5_image_token = "https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/be706282-2978-42a0-aaa2-73881aad94e9/width=1024/00049-2287632957-1girl,face,curly%20hair,red%20hair,white%20background,.jpeg"; - - let user_token = user_token; + let sd1_5_image_token = "https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/be706282-2978-42a0-aaa2-73881aad94e9/width=1024/00049-2287632957-1girl,face,curly%20hair,red%20hair,white%20background,.jpeg"; // create a loop that loops from 1 to 100 for i in 1..=100 { diff --git a/crates/cli/dev_database_seed/src/seeding/seed_media_files.rs b/crates/cli/dev_database_seed/src/seeding/seed_media_files.rs index 15f8959ef6..1e3f2c3c80 100644 --- a/crates/cli/dev_database_seed/src/seeding/seed_media_files.rs +++ b/crates/cli/dev_database_seed/src/seeding/seed_media_files.rs @@ -3,7 +3,7 @@ use std::path::Path; use log::{info, warn}; use sqlx::{MySql, Pool}; -use buckets::public::media_files::original_file::MediaFileBucketPath; +use buckets::public::media_files::bucket_file_path::MediaFileBucketPath; use enums::by_table::media_files::media_file_type::MediaFileType; use enums::common::visibility::Visibility; use errors::AnyhowResult; diff --git a/crates/cli/dev_database_seed/src/seeding/zero_shot_tts.rs b/crates/cli/dev_database_seed/src/seeding/zero_shot_tts.rs index d01c359d13..196c36b6ef 100644 --- a/crates/cli/dev_database_seed/src/seeding/zero_shot_tts.rs +++ b/crates/cli/dev_database_seed/src/seeding/zero_shot_tts.rs @@ -1,7 +1,7 @@ use log::info; use sqlx::{MySql, Pool}; -use buckets::public::media_files::original_file::MediaFileBucketPath; +use buckets::public::media_files::bucket_file_path::MediaFileBucketPath; use cloud_storage::bucket_client::BucketClient; use enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory; use enums::by_table::media_uploads::media_upload_type::MediaUploadType; diff --git a/crates/cli/dev_upload_media_file/src/main.rs b/crates/cli/dev_upload_media_file/src/main.rs index 4112093b85..3928071c5d 100644 --- a/crates/cli/dev_upload_media_file/src/main.rs +++ b/crates/cli/dev_upload_media_file/src/main.rs @@ -3,7 +3,7 @@ use std::time::Duration; use log::info; use sqlx::mysql::MySqlPoolOptions; -use buckets::public::media_files::original_file::MediaFileBucketPath; +use buckets::public::media_files::bucket_file_path::MediaFileBucketPath; use cloud_storage::bucket_client::BucketClient; use config::shared_constants::{DEFAULT_MYSQL_CONNECTION_STRING, DEFAULT_RUST_LOG}; use enums::by_table::media_files::media_file_type::MediaFileType; diff --git a/crates/lib/mysql_queries/src/queries/media_uploads/insert_media_upload.rs b/crates/lib/mysql_queries/src/queries/media_uploads/insert_media_upload.rs index 043a3b81f3..667e3751f1 100644 --- a/crates/lib/mysql_queries/src/queries/media_uploads/insert_media_upload.rs +++ b/crates/lib/mysql_queries/src/queries/media_uploads/insert_media_upload.rs @@ -2,7 +2,7 @@ use anyhow::anyhow; use log::warn; use sqlx::MySqlPool; -use buckets::public::media_uploads::original_file::MediaUploadOriginalFilePath; +use buckets::public::media_uploads::bucket_file_path::MediaUploadOriginalFilePath; use enums::by_table::media_uploads::media_upload_source::MediaUploadSource; use enums::by_table::media_uploads::media_upload_type::MediaUploadType; use enums::common::visibility::Visibility; diff --git a/crates/lib/mysql_queries/src/queries/user_bookmarks/list_user_bookmarks.rs b/crates/lib/mysql_queries/src/queries/user_bookmarks/list_user_bookmarks.rs index 1e1896a750..232c7344a6 100644 --- a/crates/lib/mysql_queries/src/queries/user_bookmarks/list_user_bookmarks.rs +++ b/crates/lib/mysql_queries/src/queries/user_bookmarks/list_user_bookmarks.rs @@ -4,10 +4,9 @@ use sqlx::MySqlPool; use enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType; use errors::AnyhowResult; -use crate::queries::user_bookmarks::list_user_bookmarks_result::UserBookmark; -use crate::queries::user_bookmarks::list_user_bookmarks_result::RawUserBookmarkRecord; -use tokens::tokens::user_bookmarks::UserBookmarkToken; +use crate::queries::user_bookmarks::list_user_bookmarks_result::RawUserBookmarkRecord; +use crate::queries::user_bookmarks::list_user_bookmarks_result::UserBookmark; pub async fn list_user_bookmarks( username: &str, diff --git a/crates/lib/mysql_queries/src/queries/voice_designer/voice_samples/insert_dataset_sample_and_media_file.rs b/crates/lib/mysql_queries/src/queries/voice_designer/voice_samples/insert_dataset_sample_and_media_file.rs index c12bf4e62a..0abda7cd4b 100644 --- a/crates/lib/mysql_queries/src/queries/voice_designer/voice_samples/insert_dataset_sample_and_media_file.rs +++ b/crates/lib/mysql_queries/src/queries/voice_designer/voice_samples/insert_dataset_sample_and_media_file.rs @@ -1,7 +1,7 @@ use anyhow::anyhow; use sqlx::MySqlPool; -use buckets::public::media_files::original_file::MediaFileBucketPath; +use buckets::public::media_files::bucket_file_path::MediaFileBucketPath; use enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory; use enums::by_table::media_files::media_file_origin_product_category::MediaFileOriginProductCategory; use enums::by_table::media_uploads::media_upload_type::MediaUploadType; diff --git a/crates/service/job/inference_job/src/job/job_types/lipsync/sad_talker/download_audio_file.rs b/crates/service/job/inference_job/src/job/job_types/lipsync/sad_talker/download_audio_file.rs index 4e6f8973e7..e90e3fc887 100644 --- a/crates/service/job/inference_job/src/job/job_types/lipsync/sad_talker/download_audio_file.rs +++ b/crates/service/job/inference_job/src/job/job_types/lipsync/sad_talker/download_audio_file.rs @@ -5,9 +5,9 @@ use log::{error, warn}; use sqlx::MySqlPool; use tempdir::TempDir; -use buckets::public::media_files::original_file::MediaFileBucketPath; -use buckets::public::media_uploads::original_file::MediaUploadOriginalFilePath; -use buckets::public::voice_conversion_results::original_file::VoiceConversionResultOriginalFilePath; +use buckets::public::media_files::bucket_file_path::MediaFileBucketPath; +use buckets::public::media_uploads::bucket_file_path::MediaUploadOriginalFilePath; +use buckets::public::voice_conversion_results::bucket_file_path::VoiceConversionResultOriginalFilePath; use cloud_storage::bucket_client::BucketClient; use jobs_common::job_progress_reporter::job_progress_reporter::JobProgressReporter; use mysql_queries::payloads::generic_inference_args::lipsync_payload::LipsyncAnimationAudioSource; diff --git a/crates/service/job/inference_job/src/job/job_types/lipsync/sad_talker/download_image_file.rs b/crates/service/job/inference_job/src/job/job_types/lipsync/sad_talker/download_image_file.rs index 3d401f0a7a..8285a78c5a 100644 --- a/crates/service/job/inference_job/src/job/job_types/lipsync/sad_talker/download_image_file.rs +++ b/crates/service/job/inference_job/src/job/job_types/lipsync/sad_talker/download_image_file.rs @@ -5,8 +5,8 @@ use log::{error, warn}; use sqlx::MySqlPool; use tempdir::TempDir; -use buckets::public::media_files::original_file::MediaFileBucketPath; -use buckets::public::media_uploads::original_file::MediaUploadOriginalFilePath; +use buckets::public::media_files::bucket_file_path::MediaFileBucketPath; +use buckets::public::media_uploads::bucket_file_path::MediaUploadOriginalFilePath; use cloud_storage::bucket_client::BucketClient; use jobs_common::job_progress_reporter::job_progress_reporter::JobProgressReporter; use mysql_queries::payloads::generic_inference_args::lipsync_payload::LipsyncAnimationImageSource; diff --git a/crates/service/job/inference_job/src/job/job_types/lipsync/sad_talker/process_job.rs b/crates/service/job/inference_job/src/job/job_types/lipsync/sad_talker/process_job.rs index cb6d563156..57852d2b4b 100644 --- a/crates/service/job/inference_job/src/job/job_types/lipsync/sad_talker/process_job.rs +++ b/crates/service/job/inference_job/src/job/job_types/lipsync/sad_talker/process_job.rs @@ -4,7 +4,7 @@ use std::time::Instant; use anyhow::anyhow; use log::{error, info, warn}; -use buckets::public::media_files::original_file::MediaFileBucketPath; +use buckets::public::media_files::bucket_file_path::MediaFileBucketPath; use enums::by_table::generic_inference_jobs::inference_result_type::InferenceResultType; use filesys::check_file_exists::check_file_exists; use filesys::file_size::file_size; diff --git a/crates/service/job/inference_job/src/job/job_types/tts/tacotron2_v2_early_fakeyou/upload_results.rs b/crates/service/job/inference_job/src/job/job_types/tts/tacotron2_v2_early_fakeyou/upload_results.rs index 87e9747a3d..e2a7547f42 100644 --- a/crates/service/job/inference_job/src/job/job_types/tts/tacotron2_v2_early_fakeyou/upload_results.rs +++ b/crates/service/job/inference_job/src/job/job_types/tts/tacotron2_v2_early_fakeyou/upload_results.rs @@ -4,7 +4,7 @@ use anyhow::anyhow; use log::info; use tempdir::TempDir; -use buckets::public::media_files::original_file::MediaFileBucketPath; +use buckets::public::media_files::bucket_file_path::MediaFileBucketPath; use enums::by_table::generic_inference_jobs::inference_result_type::InferenceResultType; use filesys::safe_delete_temp_directory::safe_delete_temp_directory; use filesys::safe_delete_temp_file::safe_delete_temp_file; diff --git a/crates/service/job/inference_job/src/job/job_types/tts/vall_e_x/process_job_create_voice.rs b/crates/service/job/inference_job/src/job/job_types/tts/vall_e_x/process_job_create_voice.rs index f83b5b764c..e210b20259 100644 --- a/crates/service/job/inference_job/src/job/job_types/tts/vall_e_x/process_job_create_voice.rs +++ b/crates/service/job/inference_job/src/job/job_types/tts/vall_e_x/process_job_create_voice.rs @@ -5,9 +5,9 @@ use std::time::Instant; use anyhow::anyhow; use log::{error, info, warn}; -use buckets::public::media_files::original_file::MediaFileBucketPath; -use buckets::public::zs_voices::directory::{ModelCategory, ModelType}; -use buckets::public::zs_voices::file::ZeroShotVoiceEmbeddingBucketPath; +use buckets::private::zs_voices::bucket_directory::{ModelCategory, ModelType}; +use buckets::private::zs_voices::bucket_file_path::ZeroShotVoiceEmbeddingBucketPath; +use buckets::public::media_files::bucket_file_path::MediaFileBucketPath; use cloud_storage::bucket_client::BucketClient; use cloud_storage::bucket_path_unifier::BucketPathUnifier; use enums::by_table::generic_inference_jobs::inference_result_type::InferenceResultType; diff --git a/crates/service/job/inference_job/src/job/job_types/tts/vall_e_x/process_job_inference_voice.rs b/crates/service/job/inference_job/src/job/job_types/tts/vall_e_x/process_job_inference_voice.rs index 20359f1e0d..76f4940796 100644 --- a/crates/service/job/inference_job/src/job/job_types/tts/vall_e_x/process_job_inference_voice.rs +++ b/crates/service/job/inference_job/src/job/job_types/tts/vall_e_x/process_job_inference_voice.rs @@ -5,9 +5,9 @@ use std::time::Instant; use anyhow::anyhow; use log::{error, info, warn}; -use buckets::public::media_files::original_file::MediaFileBucketPath; -use buckets::public::zs_voices::directory::{ModelCategory, ModelType}; -use buckets::public::zs_voices::file::ZeroShotVoiceEmbeddingBucketPath; +use buckets::private::zs_voices::bucket_directory::{ModelCategory, ModelType}; +use buckets::private::zs_voices::bucket_file_path::ZeroShotVoiceEmbeddingBucketPath; +use buckets::public::media_files::bucket_file_path::MediaFileBucketPath; use cloud_storage::bucket_client::BucketClient; use cloud_storage::bucket_path_unifier::BucketPathUnifier; use enums::by_table::generic_inference_jobs::inference_result_type::InferenceResultType; diff --git a/crates/service/job/inference_job/src/job/job_types/vc/rvc_v2/process_job.rs b/crates/service/job/inference_job/src/job/job_types/vc/rvc_v2/process_job.rs index 74496b6abc..158f304a2b 100644 --- a/crates/service/job/inference_job/src/job/job_types/vc/rvc_v2/process_job.rs +++ b/crates/service/job/inference_job/src/job/job_types/vc/rvc_v2/process_job.rs @@ -5,8 +5,8 @@ use std::time::Instant; use anyhow::anyhow; use log::{error, info, warn}; -use buckets::public::media_files::original_file::MediaFileBucketPath; -use buckets::public::media_uploads::original_file::MediaUploadOriginalFilePath; +use buckets::public::media_files::bucket_file_path::MediaFileBucketPath; +use buckets::public::media_uploads::bucket_file_path::MediaUploadOriginalFilePath; use enums::by_table::generic_inference_jobs::inference_result_type::InferenceResultType; use filesys::check_file_exists::check_file_exists; use filesys::create_dir_all_if_missing::create_dir_all_if_missing; diff --git a/crates/service/job/inference_job/src/job/job_types/vc/so_vits_svc/process_job.rs b/crates/service/job/inference_job/src/job/job_types/vc/so_vits_svc/process_job.rs index f5d7fa1b89..e02716e323 100644 --- a/crates/service/job/inference_job/src/job/job_types/vc/so_vits_svc/process_job.rs +++ b/crates/service/job/inference_job/src/job/job_types/vc/so_vits_svc/process_job.rs @@ -4,8 +4,8 @@ use std::time::Instant; use anyhow::anyhow; use log::{error, info, warn}; -use buckets::public::media_files::original_file::MediaFileBucketPath; -use buckets::public::media_uploads::original_file::MediaUploadOriginalFilePath; +use buckets::public::media_files::bucket_file_path::MediaFileBucketPath; +use buckets::public::media_uploads::bucket_file_path::MediaUploadOriginalFilePath; use enums::by_table::generic_inference_jobs::inference_result_type::InferenceResultType; use filesys::check_file_exists::check_file_exists; use filesys::create_dir_all_if_missing::create_dir_all_if_missing; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/inference_job/get_inference_job_status.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/inference_job/get_inference_job_status.rs index 96be5ed7d7..ea3e6f8f15 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/inference_job/get_inference_job_status.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/inference_job/get_inference_job_status.rs @@ -9,8 +9,8 @@ use chrono::{DateTime, Utc}; use log::error; use r2d2_redis::redis::{Commands, RedisResult}; -use buckets::public::media_files::original_file::MediaFileBucketPath; -use buckets::public::voice_conversion_results::original_file::VoiceConversionResultOriginalFilePath; +use buckets::public::media_files::bucket_file_path::MediaFileBucketPath; +use buckets::public::voice_conversion_results::bucket_file_path::VoiceConversionResultOriginalFilePath; use enums::by_table::generic_inference_jobs::frontend_failure_category::FrontendFailureCategory; use enums::by_table::generic_inference_jobs::inference_category::InferenceCategory; use enums::common::job_status_plus::JobStatusPlus; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/get_media_file.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/get_media_file.rs index 021d4db258..b18f8af8da 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/get_media_file.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/get_media_file.rs @@ -8,7 +8,7 @@ use actix_web::web::Path; use chrono::{DateTime, Utc}; use log::warn; -use buckets::public::media_files::original_file::MediaFileBucketPath; +use buckets::public::media_files::bucket_file_path::MediaFileBucketPath; use enums::by_table::media_files::media_file_type::MediaFileType; use enums::common::visibility::Visibility; use mysql_queries::queries::media_files::get_media_file::get_media_file; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_uploads/common/handle_upload.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_uploads/common/handle_upload.rs index 792af74603..2d79cab2e7 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/media_uploads/common/handle_upload.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_uploads/common/handle_upload.rs @@ -5,7 +5,7 @@ use actix_multipart::Multipart; use actix_web::{HttpRequest, web}; use log::{error, info, warn}; -use buckets::public::media_uploads::original_file::MediaUploadOriginalFilePath; +use buckets::public::media_uploads::bucket_file_path::MediaUploadOriginalFilePath; use enums::by_table::media_uploads::media_upload_source::MediaUploadSource; use enums::by_table::media_uploads::media_upload_type::MediaUploadType; use enums::common::visibility::Visibility; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/tts/get_tts_inference_job_status.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/tts/get_tts_inference_job_status.rs index be43c33d8a..20dab038b7 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/tts/get_tts_inference_job_status.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/tts/get_tts_inference_job_status.rs @@ -8,7 +8,7 @@ use actix_web::web::Path; use chrono::{DateTime, Utc}; use log::{error, log}; use r2d2_redis::redis::{Commands, RedisResult}; -use buckets::public::media_files::original_file::MediaFileBucketPath; +use buckets::public::media_files::bucket_file_path::MediaFileBucketPath; use mysql_queries::queries::generic_inference::web::get_inference_job_status::get_inference_job_status; use mysql_queries::queries::tts::tts_inference_jobs::get_tts_inference_job_status::get_tts_inference_job_status; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voice_dataset_samples/upload_zs_sample.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voice_dataset_samples/upload_zs_sample.rs index b257ce9c14..004d303f44 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voice_dataset_samples/upload_zs_sample.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voice_dataset_samples/upload_zs_sample.rs @@ -6,7 +6,7 @@ use actix_web::{HttpRequest, HttpResponse, ResponseError, web}; use hyper::StatusCode; use log::{error, info, warn}; use once_cell::sync::Lazy; -use buckets::public::media_files::original_file::MediaFileBucketPath; +use buckets::public::media_files::bucket_file_path::MediaFileBucketPath; use enums::by_table::generic_inference_jobs::inference_input_source_token_type::InferenceInputSourceTokenType::MediaUpload; use enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory; use enums::by_table::media_uploads::media_upload_type::MediaUploadType; From d9fe4e56a0556426ad041f35c07dae8007499ef8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Dec 2023 08:00:32 +0000 Subject: [PATCH 015/124] Bump version-sync from 0.8.1 to 0.9.5 Bumps [version-sync](https://github.com/mgeisler/version-sync) from 0.8.1 to 0.9.5. - [Release notes](https://github.com/mgeisler/version-sync/releases) - [Commits](https://github.com/mgeisler/version-sync/compare/0.8.1...0.9.5) --- updated-dependencies: - dependency-name: version-sync dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Cargo.lock | 460 +++++++++++++--------------- crates/vendor/limitation/Cargo.toml | 2 +- 2 files changed, 209 insertions(+), 253 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8fe281f68c..cfd5d64312 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -78,7 +78,7 @@ dependencies = [ "log", "mime", "mime_guess", - "percent-encoding 2.3.1", + "percent-encoding", "pin-project-lite", ] @@ -110,7 +110,7 @@ dependencies = [ "language-tags", "local-channel", "mime", - "percent-encoding 2.3.1", + "percent-encoding", "pin-project-lite", "rand 0.8.5", "sha1 0.10.6", @@ -127,7 +127,7 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" dependencies = [ - "quote 1.0.33", + "quote", "syn 2.0.39", ] @@ -164,8 +164,8 @@ checksum = "0a0a77f836d869f700e5b47ac7c3c8b9c8bc82e4aec861954c6198abee3ebd4d" dependencies = [ "darling 0.20.3", "parse-size", - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "syn 2.0.39", ] @@ -268,7 +268,7 @@ dependencies = [ "smallvec 1.11.2", "socket2 0.5.5", "time 0.3.30", - "url 2.5.0", + "url", ] [[package]] @@ -296,8 +296,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb1f50ebbb30eca122b188319a4398b3f7bb4a8cdf50ecfb73bfc6a3c3ce54f5" dependencies = [ "actix-router", - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "syn 2.0.39", ] @@ -307,8 +307,8 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c7db3d5a9718568e4cf4a537cfd7070e6e6ff7481510d0237fb529ac850f6d3" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "syn 2.0.39", ] @@ -416,8 +416,8 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f9afe97decc070be1864d96ab118383abed1c58fc09696663666049431110c5" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -633,8 +633,8 @@ version = "0.1.74" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "syn 2.0.39", ] @@ -681,7 +681,7 @@ dependencies = [ "native-tls", "serde", "serde_json", - "url 2.5.0", + "url", ] [[package]] @@ -715,7 +715,7 @@ dependencies = [ "serde", "thiserror", "time 0.3.30", - "url 2.5.0", + "url", ] [[package]] @@ -811,7 +811,7 @@ dependencies = [ "serde_json", "sqlx", "tokio", - "toml", + "toml 0.5.11", "url_config", ] @@ -1142,8 +1142,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" dependencies = [ "heck", - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "syn 2.0.39", ] @@ -1252,7 +1252,7 @@ dependencies = [ "anyhow", "easyenv", "my-workspace-hack", - "url 2.5.0", + "url", ] [[package]] @@ -1278,7 +1278,7 @@ dependencies = [ "rand 0.8.5", "serde", "tempfile", - "toml", + "toml 0.5.11", "uuid 0.8.2", ] @@ -1294,7 +1294,7 @@ version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" dependencies = [ - "percent-encoding 2.3.1", + "percent-encoding", "time 0.3.30", "version_check", ] @@ -1485,7 +1485,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" dependencies = [ - "quote 1.0.33", + "quote", "syn 2.0.39", ] @@ -1527,8 +1527,8 @@ checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "strsim 0.10.0", "syn 1.0.109", ] @@ -1541,8 +1541,8 @@ checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "strsim 0.10.0", "syn 1.0.109", ] @@ -1555,8 +1555,8 @@ checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" dependencies = [ "fnv", "ident_case", - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "strsim 0.10.0", "syn 2.0.39", ] @@ -1568,7 +1568,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" dependencies = [ "darling_core 0.13.4", - "quote 1.0.33", + "quote", "syn 1.0.109", ] @@ -1579,7 +1579,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" dependencies = [ "darling_core 0.14.4", - "quote 1.0.33", + "quote", "syn 1.0.109", ] @@ -1590,7 +1590,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core 0.20.3", - "quote 1.0.33", + "quote", "syn 2.0.39", ] @@ -1693,8 +1693,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f" dependencies = [ "darling 0.14.4", - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -1715,8 +1715,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" dependencies = [ "convert_case", - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "rustc_version 0.4.0", "syn 1.0.109", ] @@ -1788,8 +1788,8 @@ dependencies = [ "byteorder", "diesel_derives", "mysqlclient-sys", - "percent-encoding 2.3.1", - "url 2.5.0", + "percent-encoding", + "url", ] [[package]] @@ -1799,8 +1799,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef8337737574f55a468005a83499da720f20c65586241ffea339db9ecdfd2b44" dependencies = [ "diesel_table_macro_syntax", - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "syn 2.0.39", ] @@ -1875,8 +1875,8 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "syn 2.0.39", ] @@ -2030,13 +2030,13 @@ dependencies = [ "bytes 1.5.0", "dyn-clone", "lazy_static", - "percent-encoding 2.3.1", + "percent-encoding", "reqwest", "rustc_version 0.2.3", "serde", "serde_json", "serde_with", - "url 2.5.0", + "url", "void", ] @@ -2177,7 +2177,7 @@ dependencies = [ "sqlx-core", "sqlx-mysql", "strum", - "toml", + "toml 0.5.11", "utoipa", ] @@ -2347,7 +2347,7 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ - "percent-encoding 2.3.1", + "percent-encoding", ] [[package]] @@ -2475,8 +2475,8 @@ version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "syn 2.0.39", ] @@ -2743,8 +2743,8 @@ dependencies = [ "log", "mac", "markup5ever", - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -2828,7 +2828,7 @@ dependencies = [ "serde_json", "serde_qs 0.8.5", "serde_urlencoded", - "url 2.5.0", + "url", ] [[package]] @@ -2909,7 +2909,7 @@ dependencies = [ "http 1.0.0", "http-body 1.0.0", "pin-project-lite", - "tokio 1.34.0", + "tokio", "want", ] @@ -2937,7 +2937,7 @@ dependencies = [ "hyper 1.0.1", "hyper-util", "native-tls", - "tokio 1.34.0", + "tokio", "tokio-native-tls", "tower-service", ] @@ -2956,7 +2956,7 @@ dependencies = [ "hyper 1.0.1", "pin-project-lite", "socket2 0.5.5", - "tokio 1.34.0", + "tokio", "tower", "tower-service", "tracing", @@ -2999,17 +2999,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" -[[package]] -name = "idna" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", -] - [[package]] name = "idna" version = "0.5.0" @@ -3176,15 +3165,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "itertools" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.10.5" @@ -3330,7 +3310,7 @@ dependencies = [ "futures-util", "hostname", "httpdate", - "idna 0.5.0", + "idna", "mime", "native-tls", "nom", @@ -3338,7 +3318,7 @@ dependencies = [ "quoted_printable", "socket2 0.5.5", "tokio", - "url 2.5.0", + "url", ] [[package]] @@ -3539,20 +3519,14 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" -[[package]] -name = "matches" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" - [[package]] name = "maybe-async" version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f1b8c13cb1f814b634a96b2c725449fe7ed464a7b8781de8688be5ffbd3f305" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -3758,8 +3732,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ce75669015c4f47b289fd4d4f56e894e4c96003ffdf3ac51313126f94c6cbb" dependencies = [ "cfg-if 1.0.0", - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -3843,7 +3817,7 @@ dependencies = [ "twitch_oauth2", "unicode-bidi", "unicode-normalization", - "url 2.5.0", + "url", "void", "winapi 0.3.9", "windows-sys 0.48.0", @@ -3875,7 +3849,7 @@ dependencies = [ "sqlx", "tokens", "tokio", - "toml", + "toml 0.5.11", ] [[package]] @@ -4147,8 +4121,8 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "syn 2.0.39", ] @@ -4298,12 +4272,6 @@ dependencies = [ "base64ct", ] -[[package]] -name = "percent-encoding" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" - [[package]] name = "percent-encoding" version = "2.3.1" @@ -4367,8 +4335,8 @@ checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" dependencies = [ "phf_generator 0.11.2", "phf_shared 0.11.2", - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "syn 2.0.39", ] @@ -4405,8 +4373,8 @@ version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "syn 2.0.39", ] @@ -4517,8 +4485,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "syn 1.0.109", "version_check", ] @@ -4529,20 +4497,11 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "version_check", ] -[[package]] -name = "proc-macro2" -version = "0.4.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -dependencies = [ - "unicode-xid", -] - [[package]] name = "proc-macro2" version = "1.0.69" @@ -4561,17 +4520,6 @@ dependencies = [ "cc", ] -[[package]] -name = "pulldown-cmark" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1b74cc784b038a9921fd1a48310cc2e238101aa8ae0b94201e2d85121dd68b5" -dependencies = [ - "bitflags 1.3.2", - "memchr", - "unicase", -] - [[package]] name = "pulldown-cmark" version = "0.9.3" @@ -4613,22 +4561,13 @@ dependencies = [ "memchr", ] -[[package]] -name = "quote" -version = "0.6.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" -dependencies = [ - "proc-macro2 0.4.30", -] - [[package]] name = "quote" version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" dependencies = [ - "proc-macro2 1.0.69", + "proc-macro2", ] [[package]] @@ -4797,7 +4736,7 @@ dependencies = [ "dtoa 0.4.8", "futures 0.1.31", "itoa 0.4.8", - "percent-encoding 2.3.1", + "percent-encoding", "sha1 0.6.1", "tokio-codec", "tokio-executor", @@ -4805,7 +4744,7 @@ dependencies = [ "tokio-sync", "tokio-tcp", "tokio-uds", - "url 2.5.0", + "url", ] [[package]] @@ -4818,9 +4757,9 @@ dependencies = [ "combine 4.6.6", "dtoa 0.4.8", "itoa 0.4.8", - "percent-encoding 2.3.1", + "percent-encoding", "sha1 0.6.1", - "url 2.5.0", + "url", ] [[package]] @@ -4834,13 +4773,13 @@ dependencies = [ "combine 4.6.6", "futures-util", "itoa 1.0.9", - "percent-encoding 2.3.1", + "percent-encoding", "pin-project-lite", "ryu", "sha1 0.6.1", "tokio", "tokio-util", - "url 2.5.0", + "url", ] [[package]] @@ -4955,7 +4894,7 @@ dependencies = [ "mime", "native-tls", "once_cell", - "percent-encoding 2.3.1", + "percent-encoding", "pin-project-lite", "serde", "serde_json", @@ -4965,7 +4904,7 @@ dependencies = [ "tokio-native-tls", "tokio-util", "tower-service", - "url 2.5.0", + "url", "wasm-bindgen", "wasm-bindgen-futures", "wasm-streams", @@ -4982,7 +4921,7 @@ dependencies = [ "serde", "serde_derive", "sqlx", - "toml", + "toml 0.5.11", ] [[package]] @@ -5063,8 +5002,8 @@ version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c3d8c6fd84090ae348e63a84336b112b5c3918b3bf0493a581f7bd8ee623c29" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "rust-embed-utils", "shellexpand", "syn 2.0.39", @@ -5111,7 +5050,7 @@ dependencies = [ "maybe-async", "md5", "minidom", - "percent-encoding 2.3.1", + "percent-encoding", "quick-xml 0.26.0", "reqwest", "serde", @@ -5121,7 +5060,7 @@ dependencies = [ "time 0.3.30", "tokio", "tokio-stream", - "url 2.5.0", + "url", ] [[package]] @@ -5380,7 +5319,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" dependencies = [ - "semver-parser 0.7.0", + "semver-parser", ] [[package]] @@ -5395,12 +5334,6 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -[[package]] -name = "semver-parser" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b46e1121e8180c12ff69a742aabc4f310542b6ccb69f1691689ac17fdf8618aa" - [[package]] name = "serde" version = "1.0.193" @@ -5416,8 +5349,8 @@ version = "1.0.193" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "syn 2.0.39", ] @@ -5457,7 +5390,7 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7715380eec75f029a4ef7de39a9200e0a63823176b759d055b613f5a87df6a6" dependencies = [ - "percent-encoding 2.3.1", + "percent-encoding", "serde", "thiserror", ] @@ -5468,7 +5401,7 @@ version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8cac3f1e2ca2fe333923a1ae72caca910b98ed0630bb35ef6f8c8517d6e81afa" dependencies = [ - "percent-encoding 2.3.1", + "percent-encoding", "serde", "thiserror", ] @@ -5479,11 +5412,20 @@ version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3081f5ffbb02284dda55132aa26daecedd7372a42417bbbab6f14ab7d6bb9145" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "syn 2.0.39", ] +[[package]] +name = "serde_spanned" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -5513,8 +5455,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" dependencies = [ "darling 0.13.4", - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -5538,8 +5480,8 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "syn 2.0.39", ] @@ -5692,8 +5634,8 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "133659a15339456eeeb07572eb02a91c91e9815e9cbc89566944d2c8d3efdbf6" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -5824,7 +5766,7 @@ dependencies = [ "native-tls", "once_cell", "paste", - "percent-encoding 2.3.1", + "percent-encoding", "rustls 0.21.9", "rustls-pemfile", "serde", @@ -5836,7 +5778,7 @@ dependencies = [ "tokio", "tokio-stream", "tracing", - "url 2.5.0", + "url", "webpki-roots 0.25.3", ] @@ -5846,8 +5788,8 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89961c00dc4d7dffb7aee214964b065072bff69e36ddb9e2c107541f75e4f2a5" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "sqlx-core", "sqlx-macros-core", "syn 1.0.109", @@ -5865,8 +5807,8 @@ dependencies = [ "heck", "hex", "once_cell", - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "serde", "serde_json", "sha2 0.10.8", @@ -5877,7 +5819,7 @@ dependencies = [ "syn 1.0.109", "tempfile", "tokio", - "url 2.5.0", + "url", ] [[package]] @@ -5909,7 +5851,7 @@ dependencies = [ "md-5 0.10.6", "memchr", "once_cell", - "percent-encoding 2.3.1", + "percent-encoding", "rand 0.8.5", "rsa", "serde", @@ -5979,11 +5921,11 @@ dependencies = [ "futures-util", "libsqlite3-sys", "log", - "percent-encoding 2.3.1", + "percent-encoding", "serde", "sqlx-core", "tracing", - "url 2.5.0", + "url", "urlencoding", ] @@ -6086,7 +6028,7 @@ dependencies = [ "native-tls", "once_cell", "pin-project-lite", - "pulldown-cmark 0.9.3", + "pulldown-cmark", "r2d2_redis", "rand 0.8.5", "redis_caching", @@ -6107,7 +6049,7 @@ dependencies = [ "time 0.3.30", "tokens", "tokio", - "toml", + "toml 0.5.11", "tts_common", "twitch_common", "twitch_oauth2", @@ -6150,8 +6092,8 @@ checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" dependencies = [ "phf_generator 0.10.0", "phf_shared 0.10.0", - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", ] [[package]] @@ -6193,8 +6135,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" dependencies = [ "heck", - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "rustversion", "syn 2.0.39", ] @@ -6390,25 +6332,14 @@ dependencies = [ "symphonia-metadata", ] -[[package]] -name = "syn" -version = "0.15.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" -dependencies = [ - "proc-macro2 0.4.30", - "quote 0.6.13", - "unicode-xid", -] - [[package]] name = "syn" version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "unicode-ident", ] @@ -6418,8 +6349,8 @@ version = "2.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "unicode-ident", ] @@ -6525,8 +6456,8 @@ version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "syn 2.0.39", ] @@ -6619,7 +6550,7 @@ dependencies = [ "sqlx", "sqlx-core", "strum", - "toml", + "toml 0.5.11", "utoipa", ] @@ -6680,8 +6611,8 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "syn 2.0.39", ] @@ -6818,6 +6749,40 @@ dependencies = [ "serde", ] +[[package]] +name = "toml" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "tower" version = "0.4.13" @@ -6828,7 +6793,7 @@ dependencies = [ "futures-util", "pin-project", "pin-project-lite", - "tokio 1.34.0", + "tokio", "tower-layer", "tower-service", "tracing", @@ -6864,8 +6829,8 @@ version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "syn 2.0.39", ] @@ -6984,7 +6949,7 @@ dependencies = [ "rustls-native-certs", "sha-1", "thiserror", - "url 2.5.0", + "url", "utf-8", "webpki", ] @@ -7014,7 +6979,7 @@ dependencies = [ "my-workspace-hack", "mysql_queries", "native-tls", - "pulldown-cmark 0.9.3", + "pulldown-cmark", "r2d2_redis", "rand 0.8.5", "redis_common", @@ -7029,7 +6994,7 @@ dependencies = [ "tokens", "tokio", "tokio-tungstenite", - "toml", + "toml 0.5.11", "tts_common", "twitch_api2", "twitch_common", @@ -7059,7 +7024,7 @@ dependencies = [ "thiserror", "twitch_oauth2", "typed-builder", - "url 2.5.0", + "url", "version_check", ] @@ -7095,7 +7060,7 @@ dependencies = [ "serde", "serde_json", "thiserror", - "url 2.5.0", + "url", ] [[package]] @@ -7104,8 +7069,8 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a46ee5bd706ff79131be9c94e7edcb82b703c487766a114434e5790361cf08c5" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -7157,12 +7122,6 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" -[[package]] -name = "unicode-xid" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" - [[package]] name = "unicode_categories" version = "0.1.1" @@ -7190,17 +7149,6 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" -[[package]] -name = "url" -version = "1.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" -dependencies = [ - "idna 0.1.5", - "matches", - "percent-encoding 1.0.1", -] - [[package]] name = "url" version = "2.5.0" @@ -7208,8 +7156,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", - "idna 0.5.0", - "percent-encoding 2.3.1", + "idna", + "percent-encoding", "serde", ] @@ -7236,7 +7184,7 @@ version = "0.0.1" dependencies = [ "my-workspace-hack", "once_cell", - "pulldown-cmark 0.9.3", + "pulldown-cmark", "regex", "unicode-segmentation", ] @@ -7282,7 +7230,7 @@ dependencies = [ "strum_macros", "time 0.3.30", "tokens", - "toml", + "toml 0.5.11", "user_input_common", ] @@ -7317,8 +7265,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f0b6f4667edd64be0e820d6631a60433a269710b6ee89ac39525b872b76d61d" dependencies = [ "proc-macro-error", - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "regex", "syn 2.0.39", ] @@ -7368,18 +7316,17 @@ checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" [[package]] name = "version-sync" -version = "0.8.1" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "844f3d3a2467f15cb999f5af7775f6e108ac546d4f42365832ed4c755404f806" +checksum = "835169da0173ea373ddf5987632aac1f918967fbbe58195e304342282efa6089" dependencies = [ - "itertools 0.8.2", - "proc-macro2 0.4.30", - "pulldown-cmark 0.4.1", + "proc-macro2", + "pulldown-cmark", "regex", - "semver-parser 0.9.0", - "syn 0.15.44", - "toml", - "url 1.7.2", + "semver 1.0.20", + "syn 2.0.39", + "toml 0.7.8", + "url", ] [[package]] @@ -7516,8 +7463,8 @@ dependencies = [ "bumpalo", "log", "once_cell", - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "syn 2.0.39", "wasm-bindgen-shared", ] @@ -7540,7 +7487,7 @@ version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" dependencies = [ - "quote 1.0.33", + "quote", "wasm-bindgen-macro-support", ] @@ -7550,8 +7497,8 @@ version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "syn 2.0.39", "wasm-bindgen-backend", "wasm-bindgen-shared", @@ -7681,7 +7628,7 @@ dependencies = [ "sqlx", "time 0.3.30", "tokio", - "toml", + "toml 0.5.11", "twitch_api2", "twitch_common", "twitch_oauth2", @@ -7884,6 +7831,15 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +[[package]] +name = "winnow" +version = "0.5.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c830786f7720c2fd27a1a0e27a709dbd3c4d009b56d098fc742d4f4eab91fe2" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.50.0" @@ -7919,8 +7875,8 @@ version = "0.7.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd7e48ccf166952882ca8bd778a43502c64f33bf94c12ebe2a7f08e5a0f6689f" dependencies = [ - "proc-macro2 1.0.69", - "quote 1.0.33", + "proc-macro2", + "quote", "syn 2.0.39", ] diff --git a/crates/vendor/limitation/Cargo.toml b/crates/vendor/limitation/Cargo.toml index 51f1626635..d13d4d9d2d 100644 --- a/crates/vendor/limitation/Cargo.toml +++ b/crates/vendor/limitation/Cargo.toml @@ -28,4 +28,4 @@ my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" } [dev-dependencies] tokio = "1.34.0" -version-sync = "0.8.1" +version-sync = "0.9.5" From f9ff9b8c9ffd6ec520418d970bfd73ce5308e661 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Tue, 12 Dec 2023 11:57:42 -0500 Subject: [PATCH 016/124] Kill newrelic. This is painful to keep upgrading Keeping the vendor directory because we may introduce later. We've already done some upkeep. --- Cargo.lock | 189 +++--------------- Cargo.toml | 3 +- .../service/job/email_sender_job/Cargo.toml | 3 - crates/service/job/inference_job/Cargo.toml | 3 - .../job/inference_job/src/job_dependencies.rs | 5 - crates/service/job/inference_job/src/main.rs | 9 - .../service/job/tts_inference_job/Cargo.toml | 3 - .../src/job_steps/job_args.rs | 5 - .../src/job_steps/process_single_job.rs | 47 +---- .../service/job/tts_inference_job/src/main.rs | 88 +++----- 10 files changed, 64 insertions(+), 291 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cfd5d64312..25191d742f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -103,7 +103,7 @@ dependencies = [ "flate2", "futures-core", "h2", - "http 0.2.11", + "http", "httparse", "httpdate", "itoa 1.0.9", @@ -176,7 +176,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d66ff4d247d2b160861fa2866457e85706833527840e4133f8f49aa423a38799" dependencies = [ "bytestring", - "http 0.2.11", + "http", "regex", "serde", "tracing", @@ -614,8 +614,8 @@ dependencies = [ "hex", "hmac 0.12.1", "http-types", - "hyper 0.14.27", - "hyper-tls 0.5.0", + "hyper", + "hyper-tls", "serde", "serde_json", "serde_path_to_error", @@ -676,7 +676,7 @@ version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fcf00bc6d5abb29b5f97e3c61a90b6d3caa12f3faf897d4a3e3607c050a35a7" dependencies = [ - "http 0.2.11", + "http", "log", "native-tls", "serde", @@ -1924,7 +1924,7 @@ dependencies = [ "google_drive_common", "hashing", "hostname", - "hyper 0.14.27", + "hyper", "jobs_common", "log", "mimetypes", @@ -2114,7 +2114,7 @@ dependencies = [ "filesys", "hashing", "hostname", - "hyper 0.14.27", + "hyper", "images", "jobs_common", "lfu", @@ -2599,7 +2599,7 @@ dependencies = [ "futures-core", "futures-sink", "futures-util", - "http 0.2.11", + "http", "indexmap", "slab", "tokio", @@ -2759,17 +2759,6 @@ dependencies = [ "itoa 1.0.9", ] -[[package]] -name = "http" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea" -dependencies = [ - "bytes 1.5.0", - "fnv", - "itoa 1.0.9", -] - [[package]] name = "http-body" version = "0.4.5" @@ -2777,30 +2766,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" dependencies = [ "bytes 1.5.0", - "http 0.2.11", - "pin-project-lite", -] - -[[package]] -name = "http-body" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643" -dependencies = [ - "bytes 1.5.0", - "http 1.0.0", -] - -[[package]] -name = "http-body-util" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cb79eb393015dadd30fc252023adb0b2400a0caee0fa2a077e6e21a551e840" -dependencies = [ - "bytes 1.5.0", - "futures-util", - "http 1.0.0", - "http-body 1.0.0", + "http", "pin-project-lite", ] @@ -2820,7 +2786,7 @@ dependencies = [ "async-channel", "base64 0.13.1", "futures-lite", - "http 0.2.11", + "http", "infer 0.2.3", "pin-project-lite", "rand 0.7.3", @@ -2884,8 +2850,8 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http 0.2.11", - "http-body 0.4.5", + "http", + "http-body", "httparse", "httpdate", "itoa 1.0.9", @@ -2897,22 +2863,6 @@ dependencies = [ "want", ] -[[package]] -name = "hyper" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "403f9214f3e703236b221f1a9cd88ec8b4adfa5296de01ab96216361f4692f56" -dependencies = [ - "bytes 1.5.0", - "futures-channel", - "futures-util", - "http 1.0.0", - "http-body 1.0.0", - "pin-project-lite", - "tokio", - "want", -] - [[package]] name = "hyper-tls" version = "0.5.0" @@ -2920,48 +2870,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes 1.5.0", - "hyper 0.14.27", + "hyper", "native-tls", "tokio", "tokio-native-tls", ] -[[package]] -name = "hyper-tls" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" -dependencies = [ - "bytes 1.5.0", - "http-body-util", - "hyper 1.0.1", - "hyper-util", - "native-tls", - "tokio", - "tokio-native-tls", - "tower-service", -] - -[[package]] -name = "hyper-util" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ca339002caeb0d159cc6e023dff48e199f081e42fa039895c7c6f38b37f2e9d" -dependencies = [ - "bytes 1.5.0", - "futures-channel", - "futures-util", - "http 1.0.0", - "http-body 1.0.0", - "hyper 1.0.1", - "pin-project-lite", - "socket2 0.5.5", - "tokio", - "tower", - "tower-service", - "tracing", -] - [[package]] name = "iana-time-zone" version = "0.1.58" @@ -3095,7 +3009,7 @@ dependencies = [ "filesys", "hashing", "hostname", - "hyper 0.14.27", + "hyper", "images", "jobs_common", "lfu", @@ -3105,7 +3019,6 @@ dependencies = [ "mimetypes", "my-workspace-hack", "mysql_queries", - "newrelic-telemetry", "once_cell", "r2d2_redis", "redis_common", @@ -3772,7 +3685,7 @@ dependencies = [ "hashbrown 0.14.2", "heck", "hmac 0.12.1", - "hyper 0.14.27", + "hyper", "indexmap", "lazy_static", "libc", @@ -3903,25 +3816,6 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" -[[package]] -name = "newrelic-telemetry" -version = "0.1.0" -dependencies = [ - "anyhow", - "env_logger", - "flate2", - "futures 0.3.29", - "hyper 0.14.27", - "hyper-tls 0.6.0", - "log", - "my-workspace-hack", - "rand 0.8.5", - "serde", - "serde_json", - "tokio", - "uuid 0.8.2", -] - [[package]] name = "nix" version = "0.26.4" @@ -4884,10 +4778,10 @@ dependencies = [ "futures-core", "futures-util", "h2", - "http 0.2.11", - "http-body 0.4.5", - "hyper 0.14.27", - "hyper-tls 0.5.0", + "http", + "http-body", + "hyper", + "hyper-tls", "ipnet", "js-sys", "log", @@ -5045,7 +4939,7 @@ dependencies = [ "futures 0.3.29", "hex", "hmac 0.12.1", - "http 0.2.11", + "http", "log", "maybe-async", "md5", @@ -6009,7 +5903,7 @@ dependencies = [ "hmac 0.10.1", "hostname", "http_server_common", - "hyper 0.14.27", + "hyper", "infer 0.5.0", "jwt", "language-tags", @@ -6783,28 +6677,6 @@ dependencies = [ "winnow", ] -[[package]] -name = "tower" -version = "0.4.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" -dependencies = [ - "futures-core", - "futures-util", - "pin-project", - "pin-project-lite", - "tokio", - "tower-layer", - "tower-service", - "tracing", -] - -[[package]] -name = "tower-layer" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" - [[package]] name = "tower-service" version = "0.3.2" @@ -6865,7 +6737,7 @@ dependencies = [ "google_drive_common", "hashing", "hostname", - "hyper 0.14.27", + "hyper", "jobs_common", "log", "my-workspace-hack", @@ -6896,14 +6768,13 @@ dependencies = [ "filesys", "hashing", "hostname", - "hyper 0.14.27", + "hyper", "jobs_common", "lfu", "log", "memory_caching", "my-workspace-hack", "mysql_queries", - "newrelic-telemetry", "r2d2_redis", "serde", "serde_derive", @@ -6941,7 +6812,7 @@ dependencies = [ "base64 0.13.1", "byteorder", "bytes 1.5.0", - "http 0.2.11", + "http", "httparse", "log", "rand 0.8.5", @@ -6971,7 +6842,7 @@ dependencies = [ "futures 0.3.29", "futures-util", "hostname", - "hyper 0.14.27", + "hyper", "lazy_static", "log", "magic-crypt", @@ -7013,7 +6884,7 @@ dependencies = [ "chrono", "displaydoc", "futures 0.3.29", - "http 0.2.11", + "http", "once_cell", "reqwest", "serde", @@ -7053,7 +6924,7 @@ dependencies = [ "async-trait", "base64 0.13.1", "displaydoc", - "http 0.2.11", + "http", "once_cell", "rand 0.8.5", "reqwest", @@ -7357,7 +7228,7 @@ dependencies = [ "google_drive_common", "hashing", "hostname", - "hyper 0.14.27", + "hyper", "jobs_common", "log", "my-workspace-hack", @@ -7386,7 +7257,7 @@ dependencies = [ "filesys", "google_drive_common", "hostname", - "hyper 0.14.27", + "hyper", "jobs_common", "log", "my-workspace-hack", @@ -7606,7 +7477,7 @@ dependencies = [ "futures-util", "hostname", "http_server_common", - "hyper 0.14.27", + "hyper", "lazy_static", "limitation", "log", diff --git a/Cargo.toml b/Cargo.toml index 7649065a0d..1ea5d8fefc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -87,7 +87,8 @@ members = [ # Vendored code "crates/vendor/limitation", - "crates/vendor/newrelic-telemetry-sdk-rust", + # NB(bt,2023-12-12): Newrelic keeps breaking with upgrades. Kill for now. + #"crates/vendor/newrelic-telemetry-sdk-rust", # cargo-hakari workspace hack (compilation speedup hack) "crates/my-workspace-hack", diff --git a/crates/service/job/email_sender_job/Cargo.toml b/crates/service/job/email_sender_job/Cargo.toml index f72b7f7fba..733388d420 100644 --- a/crates/service/job/email_sender_job/Cargo.toml +++ b/crates/service/job/email_sender_job/Cargo.toml @@ -44,9 +44,6 @@ tts_common = { path = "../../../lib/tts_common" } # Workspace hack (faster compile times) my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" } -# Vendored code -# newrelic-telemetry = { path = "../../../vendor/newrelic-telemetry-sdk-rust" } - # External anyhow = "1.0.75" chrono = { version = "0.4.22", features = ["serde"] } diff --git a/crates/service/job/inference_job/Cargo.toml b/crates/service/job/inference_job/Cargo.toml index 9f8205ca14..199d70f522 100644 --- a/crates/service/job/inference_job/Cargo.toml +++ b/crates/service/job/inference_job/Cargo.toml @@ -41,9 +41,6 @@ tts_common = { path = "../../../lib/tts_common" } # Workspace hack (faster compile times) my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" } -# Vendored code -newrelic-telemetry = { path = "../../../vendor/newrelic-telemetry-sdk-rust" } - # External anyhow = "1.0.75" chrono = { version = "0.4.22", features = ["serde"] } diff --git a/crates/service/job/inference_job/src/job_dependencies.rs b/crates/service/job/inference_job/src/job_dependencies.rs index 504d2fb08d..79d8d703c1 100644 --- a/crates/service/job/inference_job/src/job_dependencies.rs +++ b/crates/service/job/inference_job/src/job_dependencies.rs @@ -22,7 +22,6 @@ use mysql_queries::common_inputs::container_environment_arg::ContainerEnvironmen use mysql_queries::mediators::firehose_publisher::FirehosePublisher; use mysql_queries::queries::tts::tts_models::get_tts_model_for_inference_improved::TtsModelForInferenceRecord; use mysql_queries::queries::voice_conversion::inference::get_voice_conversion_model_for_inference::VoiceConversionModelForInference; -use newrelic_telemetry::Client as NewRelicClient; use crate::job_specific_dependencies::JobSpecificDependencies; use crate::util::scoped_execution::ScopedExecution; @@ -135,10 +134,6 @@ pub struct ClientDependencies { pub job_progress_reporter: Box, pub firehose_publisher: FirehosePublisher, - - pub newrelic_client: NewRelicClient, - - pub newrelic_disabled: bool, } pub struct FileSystemDetails { diff --git a/crates/service/job/inference_job/src/main.rs b/crates/service/job/inference_job/src/main.rs index 7779535799..186e87c9f4 100644 --- a/crates/service/job/inference_job/src/main.rs +++ b/crates/service/job/inference_job/src/main.rs @@ -44,7 +44,6 @@ use memory_caching::multi_item_ttl_cache::MultiItemTtlCache; use memory_caching::ttl_key_counter::TtlKeyCounter; use mysql_queries::common_inputs::container_environment_arg::ContainerEnvironmentArg; use mysql_queries::mediators::firehose_publisher::FirehosePublisher; -use newrelic_telemetry::ClientBuilder; use crate::http_server::run_http_server::CreateServerArgs; use crate::http_server::run_http_server::launch_http_server; @@ -149,12 +148,6 @@ async fn main() -> AnyhowResult<()> { mysql_pool: mysql_pool.clone(), // NB: MySqlPool is clone/send/sync safe }; - let license_key = easyenv::get_env_string_required("NEWRELIC_API_KEY")?; - - let newrelic_disabled = easyenv::get_env_bool_or_default("IS_NEWRELIC_DISABLED", false); - - let newrelic_client = ClientBuilder::new(&license_key).build().unwrap(); - let maybe_minimum_priority = easyenv::get_env_string_optional("MAYBE_MINIMUM_PRIORITY") .map(|priority_string| { priority_string.parse::() @@ -237,8 +230,6 @@ async fn main() -> AnyhowResult<()> { clients: ClientDependencies { job_progress_reporter, firehose_publisher, - newrelic_client, - newrelic_disabled, }, job: JobSystemDependencies { system: JobSystemControls { diff --git a/crates/service/job/tts_inference_job/Cargo.toml b/crates/service/job/tts_inference_job/Cargo.toml index cbfdd24de1..2d1f6fa732 100644 --- a/crates/service/job/tts_inference_job/Cargo.toml +++ b/crates/service/job/tts_inference_job/Cargo.toml @@ -30,9 +30,6 @@ tts_common = { path = "../../../lib/tts_common" } # Workspace hack (faster compile times) my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" } -# Vendored code -newrelic-telemetry = { path = "../../../vendor/newrelic-telemetry-sdk-rust" } - # External anyhow = "1.0.75" chrono = { version = "0.4.22", features = ["serde"] } diff --git a/crates/service/job/tts_inference_job/src/job_steps/job_args.rs b/crates/service/job/tts_inference_job/src/job_steps/job_args.rs index 433c04771f..3b4296a0d3 100644 --- a/crates/service/job/tts_inference_job/src/job_steps/job_args.rs +++ b/crates/service/job/tts_inference_job/src/job_steps/job_args.rs @@ -10,7 +10,6 @@ use jobs_common::semi_persistent_cache_dir::SemiPersistentCacheDir; use memory_caching::multi_item_ttl_cache::MultiItemTtlCache; use mysql_queries::mediators::firehose_publisher::FirehosePublisher; use mysql_queries::queries::tts::tts_models::get_tts_model_for_inference::TtsModelForInferenceRecord; -use newrelic_telemetry::Client as NewRelicClient; use crate::caching::cache_miss_strategizer_multi::SyncMultiCacheMissStrategizer; use crate::caching::virtual_lfu_cache::SyncVirtualLfuCache; @@ -38,10 +37,6 @@ pub struct JobArgs { pub job_stats: JobStats, - pub newrelic_client: NewRelicClient, - - pub newrelic_disabled: bool, - pub worker_details: JobWorkerDetails, // Keep tabs of which models to hold in the sidecar memory with this virtual LRU cache diff --git a/crates/service/job/tts_inference_job/src/job_steps/process_single_job.rs b/crates/service/job/tts_inference_job/src/job_steps/process_single_job.rs index bb9cd522a8..1767a674e2 100644 --- a/crates/service/job/tts_inference_job/src/job_steps/process_single_job.rs +++ b/crates/service/job/tts_inference_job/src/job_steps/process_single_job.rs @@ -6,14 +6,13 @@ use std::fs::File; use std::io::Read; use std::path::PathBuf; -use std::time::{Instant, SystemTime, UNIX_EPOCH}; +use std::time::{SystemTime, UNIX_EPOCH}; use anyhow::anyhow; use log::{error, info, warn}; use tempdir::TempDir; use container_common::anyhow_result::AnyhowResult; -use container_common::token::random_uuid::generate_random_uuid; use filesys::check_file_exists::check_file_exists; use filesys::safe_delete_temp_directory::safe_delete_temp_directory; use filesys::safe_delete_temp_file::safe_delete_temp_file; @@ -24,7 +23,6 @@ use mysql_queries::queries::tts::tts_inference_jobs::mark_tts_inference_job_done use mysql_queries::queries::tts::tts_inference_jobs::mark_tts_inference_job_pending_and_grab_lock::mark_tts_inference_job_pending_and_grab_lock; use mysql_queries::queries::tts::tts_models::get_tts_model_for_inference::{get_tts_model_for_inference, TtsModelForInferenceRecord}; use mysql_queries::queries::tts::tts_results::insert_tts_result::{insert_tts_result, JobType}; -use newrelic_telemetry::Span; use tts_common::clean_symbols::clean_symbols; use tts_common::text_pipelines::guess_pipeline::guess_text_pipeline_heuristic; use tts_common::text_pipelines::text_pipeline_type::TextPipelineType; @@ -56,34 +54,13 @@ pub async fn process_single_job( job_args: &JobArgs, job: &AvailableTtsInferenceJob, cached_model_record: &TtsModelForInferenceRecord, -) -> Result<(Span, Span), ProcessSingleJobError> { +) -> Result<(), ProcessSingleJobError> { // NB: Hack to allow cache bypass for debug requests // This will let us iterate faster with model changes. let mut maybe_queried_model = None; let mut model_record = cached_model_record; - let start = Instant::now(); - - let span_id = generate_random_uuid(); - let trace_id = generate_random_uuid(); - let maybe_user_token = job.maybe_creator_user_token.as_deref().unwrap_or(""); - - let mut job_iteration_span = Span::new(&span_id, &trace_id, get_timestamp_millis()) - .name("single job execution") - .attribute("user_token", maybe_user_token) - .service_name("tts-inference-job"); - - let span_id = generate_random_uuid(); - let trace_id = generate_random_uuid(); - - let created_at_timestamp = (job.created_at.timestamp() as u64) * 1000; - - let mut since_creation_span = Span::new(&span_id, &trace_id, created_at_timestamp) - .name("job since creation") - .attribute("user_token", maybe_user_token) - .service_name("tts-inference-job"); - let mut job_progress_reporter = job_args .job_progress_reporter .new_tts_inference(&job.inference_job_token) @@ -100,15 +77,7 @@ pub async fn process_single_job( if !lock_acquired { warn!("Could not acquire job lock for: {:?}", &job.id); - let duration = start.elapsed(); - - since_creation_span.set_attribute("status", "failure"); - since_creation_span.set_duration(duration); - - job_iteration_span.set_attribute("status", "failure"); - job_iteration_span.set_duration(duration); - - return Ok((since_creation_span, job_iteration_span)); + return Ok(()); } info!("Lock acquired for job: {}", job.inference_job_token); @@ -448,15 +417,7 @@ pub async fn process_single_job( info!("Job {:?} complete success! Downloaded, ran inference, and uploaded. Saved model record: {}, Result Token: {}", job.id, id, &inference_result_token); - let duration = start.elapsed(); - - since_creation_span.set_attribute("status", "success"); - since_creation_span.set_duration(duration); - - job_iteration_span.set_attribute("status", "success"); - job_iteration_span.set_duration(duration); - - Ok((since_creation_span, job_iteration_span)) + Ok(()) } fn get_timestamp_millis() -> u64 { diff --git a/crates/service/job/tts_inference_job/src/main.rs b/crates/service/job/tts_inference_job/src/main.rs index 9738caa13c..db471482ac 100644 --- a/crates/service/job/tts_inference_job/src/main.rs +++ b/crates/service/job/tts_inference_job/src/main.rs @@ -45,8 +45,6 @@ use mysql_queries::queries::tts::tts_inference_jobs::list_available_tts_inferenc use mysql_queries::queries::tts::tts_inference_jobs::mark_tts_inference_job_failure::mark_tts_inference_job_failure; use mysql_queries::queries::tts::tts_inference_jobs::mark_tts_inference_job_permanently_dead::mark_tts_inference_job_permanently_dead; use mysql_queries::queries::tts::tts_models::get_tts_model_for_inference::{get_tts_model_for_inference, TtsModelForInferenceError, TtsModelForInferenceRecord}; -use newrelic_telemetry::ClientBuilder; -use newrelic_telemetry::Span; use crate::caching::cache_miss_strategizer::CacheMissStrategizer; use crate::caching::cache_miss_strategizer::CacheMissStrategy; @@ -253,12 +251,6 @@ async fn main() -> AnyhowResult<()> { easyenv::get_env_num("TTS_MODEL_RECORD_CACHE_MILLIS", 300_000)?, // Five minutes ); - let license_key = easyenv::get_env_string_required("NEWRELIC_API_KEY")?; - - let newrelic_disabled = easyenv::get_env_bool_or_default("IS_NEWRELIC_DISABLED", false); - - let newrelic_client = ClientBuilder::new(&license_key).build().unwrap(); - let maybe_minimum_priority = easyenv::get_env_string_optional("MAYBE_MINIMUM_PRIORITY") .map(|priority_string| { priority_string.parse::() @@ -301,8 +293,6 @@ async fn main() -> AnyhowResult<()> { tts_sidecar_health_check_client, }, job_stats: JobStats::new(), - newrelic_client, - newrelic_disabled, worker_details: JobWorkerDetails { is_on_prem, worker_hostname: server_hostname.clone(), @@ -344,8 +334,6 @@ async fn main_loop(job_args: JobArgs) { let mut noop_logger = NoOpLogger::new(job_args.no_op_logger_millis as i64); - let mut span_batch = Vec::new(); - let mut sort_by_priority = true; let mut sort_by_priority_count = 0; @@ -411,23 +399,11 @@ async fn main_loop(job_args: JobArgs) { needs_health_check_at_start = false; } - let mut spans = match batch_result { - Ok(spans) => spans, - Err(e) => { - warn!("Error running job batch: {:?}", e); - std::thread::sleep(Duration::from_millis(error_timeout_millis)); - error_timeout_millis += INCREASE_TIMEOUT_MILLIS; - continue; - } - }; - - if !job_args.newrelic_disabled { - span_batch.append(&mut spans); - - if span_batch.len() > 50 { - let spans_to_send = span_batch.split_off(0).into(); - job_args.newrelic_client.send_spans(spans_to_send).await; - } + if let Err(e) = batch_result { + warn!("Error running job batch: {:?}", e); + std::thread::sleep(Duration::from_millis(error_timeout_millis)); + error_timeout_millis += INCREASE_TIMEOUT_MILLIS; + continue; } error_timeout_millis = START_TIMEOUT_MILLIS; // reset @@ -441,7 +417,7 @@ async fn process_jobs( inferencer: &JobArgs, jobs: Vec, needs_health_check_at_start: bool, -) -> AnyhowResult> { +) -> AnyhowResult<()> { if needs_health_check_at_start { maybe_block_on_sidecar_health_check(&inferencer.http_clients.tts_sidecar_health_check_client).await; @@ -449,8 +425,6 @@ async fn process_jobs( let mut maybe_sidecar_health_issue = false; - let mut batch_spans = Vec::new(); - for job in jobs.into_iter() { let model_state_result = ModelState::query_model_and_check_filesystem( &job, @@ -555,44 +529,38 @@ async fn process_jobs( } let result = process_single_job(inferencer, &job, &model_state.model_record).await; - match result { - Ok((span1, span2)) => { - batch_spans.push(span1); - batch_spans.push(span2); - }, - Err(e) => { - warn!("Failure to process job: {:?}", e); + if let Err(e) = result { + warn!("Failure to process job: {:?}", e); - record_failure_and_maybe_slow_down(&inferencer.job_stats); + record_failure_and_maybe_slow_down(&inferencer.job_stats); - maybe_sidecar_health_issue = true; + maybe_sidecar_health_issue = true; - let failure_reason = "failure processing job"; - let internal_debugging_failure_reason = format!("job error: {:?}", e); + let failure_reason = "failure processing job"; + let internal_debugging_failure_reason = format!("job error: {:?}", e); - let _r = mark_tts_inference_job_failure( - &inferencer.mysql_pool, - &job, - failure_reason, - &internal_debugging_failure_reason, - inferencer.job_max_attempts, - &inferencer.get_worker_name(), - ).await; + let _r = mark_tts_inference_job_failure( + &inferencer.mysql_pool, + &job, + failure_reason, + &internal_debugging_failure_reason, + inferencer.job_max_attempts, + &inferencer.get_worker_name(), + ).await; - match e { - ProcessSingleJobError::Other(_) => {} // No-op - ProcessSingleJobError::FilesystemFull => { - // TODO: Refactor - we should stop processing all of these jobs as we'll lose out - // on this entire batch by attempting to clear the filesystem. This should be handled - // in the calling code. - delete_tts_synthesizers_from_cache(&inferencer.semi_persistent_cache)?; - } + match e { + ProcessSingleJobError::Other(_) => {} // No-op + ProcessSingleJobError::FilesystemFull => { + // TODO: Refactor - we should stop processing all of these jobs as we'll lose out + // on this entire batch by attempting to clear the filesystem. This should be handled + // in the calling code. + delete_tts_synthesizers_from_cache(&inferencer.semi_persistent_cache)?; } } } } - Ok(batch_spans) + Ok(()) } fn record_failure_and_maybe_slow_down(job_stats: &JobStats) { From 8bb82c0fe5c9b598211bc10065593760765008d6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Dec 2023 16:59:57 +0000 Subject: [PATCH 017/124] Bump async-stripe from 0.25.2 to 0.26.0 Bumps [async-stripe](https://github.com/arlyon/async-stripe) from 0.25.2 to 0.26.0. - [Release notes](https://github.com/arlyon/async-stripe/releases) - [Changelog](https://github.com/arlyon/async-stripe/blob/master/CHANGELOG.md) - [Commits](https://github.com/arlyon/async-stripe/compare/v0.25.2...v0.26.0) --- updated-dependencies: - dependency-name: async-stripe dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- Cargo.lock | 4 ++-- crates/service/plugins/billing/Cargo.toml | 2 +- crates/service/web/storyteller_web/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 25191d742f..9d10ab3e5c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -605,9 +605,9 @@ dependencies = [ [[package]] name = "async-stripe" -version = "0.25.2" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1b39347f478f57a40cbaf82cbaebb4a350acc757cda30fc7ff88707a11d1d81" +checksum = "19a0b12cb3b2df9abfaa381632e4d55b2aede9063034daaa0d0145413719a7e1" dependencies = [ "chrono", "futures-util", diff --git a/crates/service/plugins/billing/Cargo.toml b/crates/service/plugins/billing/Cargo.toml index 869eee7790..72b2ded754 100644 --- a/crates/service/plugins/billing/Cargo.toml +++ b/crates/service/plugins/billing/Cargo.toml @@ -45,7 +45,7 @@ serde_json = "1.0.108" toml = "0.5.8" # Money -async-stripe = { version = "0.25.2", default-features = false, features = ["runtime-tokio-hyper", "connect", "billing", "checkout", "webhook-events"] } +async-stripe = { version = "0.26.0", default-features = false, features = ["runtime-tokio-hyper", "connect", "billing", "checkout", "webhook-events"] } # Async traits # NB: note: `async` trait functions are not currently supported diff --git a/crates/service/web/storyteller_web/Cargo.toml b/crates/service/web/storyteller_web/Cargo.toml index c8d81cef9a..357c79c99a 100644 --- a/crates/service/web/storyteller_web/Cargo.toml +++ b/crates/service/web/storyteller_web/Cargo.toml @@ -139,7 +139,7 @@ jwt = "0.13.0" hyper = { version = "0.14.24" } # Money -async-stripe = { version = "0.25.2", default-features = false, features = ["runtime-tokio-hyper", "connect", "billing", "checkout", "webhook-events"] } +async-stripe = { version = "0.26.0", default-features = false, features = ["runtime-tokio-hyper", "connect", "billing", "checkout", "webhook-events"] } # Crypto bcrypt = "0.8" # password hashes From 2d59c5c573ff4dae82705268517e41b7a88b4648 Mon Sep 17 00:00:00 2001 From: salt Date: Tue, 12 Dec 2023 13:47:12 -0800 Subject: [PATCH 018/124] initial commit --- .env | 78 ----- Cargo.lock | 2 + .../inference_category.rs | 4 + .../inference_model_type.rs | 2 + .../generic_inference_args.rs | 10 + .../payloads/generic_inference_args/mod.rs | 3 +- .../videofilter_payload.rs | 36 ++ crates/service/job/inference_job/Cargo.toml | 2 + .../inference_job/src/job/job_types/mod.rs | 3 +- .../src/job/job_types/videofilter/mod.rs | 1 + .../rerender_a_video/categorize_error.rs | 5 + .../rerender_a_video/download_video_file.rs | 83 +++++ .../videofilter/rerender_a_video/mod.rs | 6 + .../rerender_a_video/process_jobs.rs | 316 ++++++++++++++++++ .../rerender_a_video/rerender_dependencies.rs | 15 + .../rerender_inference_command.rs | 233 +++++++++++++ .../rerender_a_video/validate_job.rs | 85 +++++ .../src/job_specific_dependencies.rs | 9 + .../service/web/storyteller_web/src/routes.rs | 1 + 19 files changed, 814 insertions(+), 80 deletions(-) delete mode 100644 .env create mode 100644 crates/lib/mysql_queries/src/payloads/generic_inference_args/videofilter_payload.rs create mode 100644 crates/service/job/inference_job/src/job/job_types/videofilter/mod.rs create mode 100644 crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/categorize_error.rs create mode 100644 crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/download_video_file.rs create mode 100644 crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/mod.rs create mode 100644 crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/process_jobs.rs create mode 100644 crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/rerender_dependencies.rs create mode 100644 crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/rerender_inference_command.rs create mode 100644 crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/validate_job.rs diff --git a/.env b/.env deleted file mode 100644 index b205c3a6b3..0000000000 --- a/.env +++ /dev/null @@ -1,78 +0,0 @@ -SERVER_ENVIRONMENT=development - -DATABASE_URL=mysql://storyteller:password@localhost/storyteller -#DATABASE_URL=mysql://root:root@localhost/storyteller -#DATABASE_URL=mysql://root@localhost/storyteller - -# Diesel-cli reads this for the migration directory to use. -# We've renamed it so the migrations are sorted near the top of the project directory tree -# (since they kind of serve as documentation) -MIGRATION_DIRECTORY=_sql/migrations/ - -# SQLX normally requires a live database to reflect upon at build time. -# This setting turns that on and requires a `sql-data.json` cache file instead. -# See https://github.com/launchbadge/sqlx/tree/master/sqlx-cli#readme -#SQLX_OFFLINE=true - -# NB(bt, 2023-03-20): -# These are used in storyteller-web, image-generation-service, and websocket-gateway. -# I'm moving them to env configs that live under storyteller-web/.env. -# This will break the other services for now. -# # We can't serve HTTPS locally without self-signed certificate nonsense. -# COOKIE_SECURE=false -# COOKIE_DOMAIN=.jungle.horse -# WEBSITE_HOMEPAGE_REDIRECT=http://jungle.horse - -# Bucket config (non-secret) -REGION_NAME=us-east1 - -TTS_DOWNLOAD_BUCKET_NAME=dev-vocodes-private-uploads -TTS_DOWNLOAD_BUCKET_ROOT=/user_uploaded_tts_models - -W2L_PRIVATE_DOWNLOAD_BUCKET_NAME=dev-vocodes-private-uploads -W2L_PUBLIC_DOWNLOAD_BUCKET_NAME=dev-vocodes-public - -PRIVATE_BUCKET_NAME=dev-vocodes-private-uploads -PUBLIC_BUCKET_NAME=dev-vocodes-public - -# Bucket roots -AUDIO_UPLOADS_BUCKET_ROOT=/user_uploaded_w2l_audio -W2L_DOWNLOAD_BUCKET_ROOT=/user_uploaded_w2l_templates -W2L_INFERENCE_OUTPUT_BUCKET_ROOT=/w2l_output - -W2L_CODE_DIRECTORY=/home/bt/dev/storyteller/storyteller-web/models/Wav2Lip -W2L_INFERENCE_SCRIPT_NAME=vocodes_process_inference.py -W2L_MODEL_FILENAME=wav2lip_gan.pth - -#W2L_MODEL_CHECKPOINT=/home/bt/models/wav2lip/s3fd-619a316812.pth -W2L_MODEL_CHECKPOINT=/home/bt/models/wav2lip/wav2lip_gan.pth -W2L_END_BUMP_FILENAME=vocodes-short-end-bump.mp4 - -W2L_DOWNLOAD_SCRIPT_NAME=vocodes_process_upload.py - -TTS_CODE_DIRECTORY=/home/bt/dev/storyteller/storyteller-ml/tts -TTS_INFERENCE_SCRIPT_NAME=vocodes_inference.py - -TACOTRON_ROOT_CODE_DIRECTORY=/home/bt/dev/storyteller/storyteller-ml/tts -TACOTRON_VIRTUAL_ENV_ACTIVATION_COMMAND="source python/bin/activate" -TACOTRON_MODEL_CHECK_SCRIPT_NAME="vocodes_model_check_tacotron.py" - -TALKNET_ROOT_CODE_DIRECTORY=/home/bt/dev/storyteller/storyteller-ml/tts -TALKNET_MODEL_CHECK_SCRIPT_NAME="vocodes_model_check_talknet.py" - -HIFIGAN_ROOT_CODE_DIRECTORY=/home/bt/dev/storyteller/storyteller-ml/tts -HIFIGAN_VIRTUAL_ENV_ACTIVATION_COMMAND="source python/bin/activate" -HIFIGAN_MODEL_CHECK_SCRIPT_NAME="vocodes_model_check_hifigan.py" - -TTS_INFERENCE_SIDECAR_HOSTNAME=localhost:8000 - -#TTS_WAVEGLOW_VOCODER_MODEL_FILENAME=waveglow_256channels_universal_v5.pt # THIS SOUNDS HORRID -#TTS_WAVEGLOW_VOCODER_MODEL_FILENAME=waveglow_256channels_v4_uberduck.pt # THIS IS TOO SMALL! 300MB vs 1.2 GB! -TTS_WAVEGLOW_VOCODER_MODEL_FILENAME=waveglow_256channels_v4.pt - -TTS_HIFIGAN_VOCODER_MODEL_FILENAME=hifigan_universal_g_02500000.pt -TTS_HIFIGAN_SUPERRES_VOCODER_MODEL_FILENAME=hifigan_superres_twilight_33000.pt - -# Development key. Permissible to check in. -NEWRELIC_API_KEY=c402be1c4c4216ec83d0cfc0851520cfFFFFNRAL -STORYTELLER_ROOT="/home/tensor/code/storyteller/" \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index bec222b29c..d8fddc06d1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3063,6 +3063,7 @@ dependencies = [ "log", "media", "memory_caching", + "mime", "mimetypes", "my-workspace-hack", "mysql_queries", @@ -3077,6 +3078,7 @@ dependencies = [ "subprocess", "subprocess_common", "tempdir", + "time 0.3.30", "tokens", "tokio 1.34.0", "tts_common", diff --git a/crates/_types/enums/src/by_table/generic_inference_jobs/inference_category.rs b/crates/_types/enums/src/by_table/generic_inference_jobs/inference_category.rs index b38f181460..b96b6fb261 100644 --- a/crates/_types/enums/src/by_table/generic_inference_jobs/inference_category.rs +++ b/crates/_types/enums/src/by_table/generic_inference_jobs/inference_category.rs @@ -25,6 +25,9 @@ pub enum InferenceCategory { #[serde(rename = "voice_conversion")] VoiceConversion, + + #[serde(rename = "rerender_a_video")] + RerenderAVideo, } // TODO(bt, 2022-12-21): This desperately needs MySQL integration tests! @@ -38,6 +41,7 @@ impl InferenceCategory { Self::LipsyncAnimation => "lipsync_animation", Self::TextToSpeech => "text_to_speech", Self::VoiceConversion => "voice_conversion", + Self::RerenderAVideo => "rerender_a_video", } } diff --git a/crates/_types/enums/src/by_table/generic_inference_jobs/inference_model_type.rs b/crates/_types/enums/src/by_table/generic_inference_jobs/inference_model_type.rs index 2a939038d6..5401430bd1 100644 --- a/crates/_types/enums/src/by_table/generic_inference_jobs/inference_model_type.rs +++ b/crates/_types/enums/src/by_table/generic_inference_jobs/inference_model_type.rs @@ -31,6 +31,8 @@ pub enum InferenceModelType { Vits, #[serde(rename = "vall_e_x")] VallEX, + #[serde(rename = "rerender_a_video")] + RerenderAVideo, } // TODO(bt, 2022-12-21): This desperately needs MySQL integration tests! diff --git a/crates/lib/mysql_queries/src/payloads/generic_inference_args/generic_inference_args.rs b/crates/lib/mysql_queries/src/payloads/generic_inference_args/generic_inference_args.rs index 541de77aa4..7ba7b0b3ef 100644 --- a/crates/lib/mysql_queries/src/payloads/generic_inference_args/generic_inference_args.rs +++ b/crates/lib/mysql_queries/src/payloads/generic_inference_args/generic_inference_args.rs @@ -3,6 +3,7 @@ use errors::AnyhowResult; use crate::payloads::generic_inference_args::lipsync_payload::LipsyncArgs; use crate::payloads::generic_inference_args::tts_payload::TTSArgs; +use crate::payloads::generic_inference_args::videofilter_payload::VideofilterVideoSource; /// Used to encode extra state for the `generic_inference_jobs` table. @@ -35,6 +36,10 @@ pub enum InferenceCategoryAbbreviated { #[serde(rename = "vc")] // NB: DO NOT CHANGE. It could break live jobs. Renamed to be fewer bytes. #[serde(alias = "voice_conversion")] VoiceConversion, + + #[serde(rename = "rr")] // NB: DO NOT CHANGE. It could break live jobs. Renamed to be fewer bytes. + #[serde(alias = "rerender_a_video")] + RerenderAVideo, } #[derive(Serialize, Deserialize, Clone, Copy, Debug)] @@ -84,6 +89,9 @@ pub enum PolymorphicInferenceArgs { #[serde(skip_serializing_if = "Option::is_none")] transpose: Option, }, + + /// Rerender a video. (Short name to save space when serializing.) + Rr(RerenderArgs) } @@ -104,6 +112,7 @@ impl InferenceCategoryAbbreviated { InferenceCategory::LipsyncAnimation => Self::LipsyncAnimation, InferenceCategory::TextToSpeech => Self::TextToSpeech, InferenceCategory::VoiceConversion => Self::VoiceConversion, + InferenceCategory::RerenderAVideo => Self::RerenderAVideo, } } @@ -112,6 +121,7 @@ impl InferenceCategoryAbbreviated { Self::LipsyncAnimation => InferenceCategory::LipsyncAnimation, Self::TextToSpeech => InferenceCategory::TextToSpeech, Self::VoiceConversion => InferenceCategory::VoiceConversion, + Self::RerenderAVideo => InferenceCategory::RerenderAVideo, } } } diff --git a/crates/lib/mysql_queries/src/payloads/generic_inference_args/mod.rs b/crates/lib/mysql_queries/src/payloads/generic_inference_args/mod.rs index 37980d38d1..e68fc5a71c 100644 --- a/crates/lib/mysql_queries/src/payloads/generic_inference_args/mod.rs +++ b/crates/lib/mysql_queries/src/payloads/generic_inference_args/mod.rs @@ -1,3 +1,4 @@ pub mod generic_inference_args; pub mod lipsync_payload; -pub mod tts_payload; \ No newline at end of file +pub mod tts_payload; +pub mod videofilter_payload; \ No newline at end of file diff --git a/crates/lib/mysql_queries/src/payloads/generic_inference_args/videofilter_payload.rs b/crates/lib/mysql_queries/src/payloads/generic_inference_args/videofilter_payload.rs new file mode 100644 index 0000000000..85335cde79 --- /dev/null +++ b/crates/lib/mysql_queries/src/payloads/generic_inference_args/videofilter_payload.rs @@ -0,0 +1,36 @@ +/// Video sources can be one of several: +/// - F: media_files (todo) +/// - U: media_uploads (legacy) +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] +pub enum VideofilterVideoSource { + // NB: DO NOT CHANGE. It could break live jobs. Renamed to be fewer bytes. + /// Media File Token (media_files table) + /// Serde cannot yet rename enum variants. + F(String), + + // NB: DO NOT CHANGE. It could break live jobs. Renamed to be fewer bytes. + /// Media Upload Token (media_uploads table) + /// Serde cannot yet rename enum variants. + U(String), +} + + +impl VideofilterVideoSource { + pub fn media_file_token(token: &str) -> Self { + VideofilterVideoSource::F(token.to_string()) + } + pub fn media_upload_token(token: &str) -> Self { + VideofilterVideoSource::U(token.to_string()) + } +} + +#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)] +pub struct RerenderArgs { + #[serde(rename = "vs")] + #[serde(skip_serializing_if = "Option::is_none")] + pub maybe_video_source: Option, + + #[serde(rename = "sd")] + #[serde(skip_serializing_if = "Option::is_none")] + pub sd_model: String, +} diff --git a/crates/service/job/inference_job/Cargo.toml b/crates/service/job/inference_job/Cargo.toml index d0008b9eac..65713e40b0 100644 --- a/crates/service/job/inference_job/Cargo.toml +++ b/crates/service/job/inference_job/Cargo.toml @@ -79,3 +79,5 @@ serde_json = "1.0.108" # include support for async fn in traits. async-trait = "0.1.58" my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" } +time = "0.3.30" +mime = "0.3.17" diff --git a/crates/service/job/inference_job/src/job/job_types/mod.rs b/crates/service/job/inference_job/src/job/job_types/mod.rs index f21a93a492..a688e281ba 100644 --- a/crates/service/job/inference_job/src/job/job_types/mod.rs +++ b/crates/service/job/inference_job/src/job/job_types/mod.rs @@ -1,3 +1,4 @@ pub mod lipsync; pub mod tts; -pub mod vc; \ No newline at end of file +pub mod vc; +pub(crate) mod videofilter; \ No newline at end of file diff --git a/crates/service/job/inference_job/src/job/job_types/videofilter/mod.rs b/crates/service/job/inference_job/src/job/job_types/videofilter/mod.rs new file mode 100644 index 0000000000..b8f301c73d --- /dev/null +++ b/crates/service/job/inference_job/src/job/job_types/videofilter/mod.rs @@ -0,0 +1 @@ +pub(crate) mod rerender_a_video; \ No newline at end of file diff --git a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/categorize_error.rs b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/categorize_error.rs new file mode 100644 index 0000000000..a1effe90c7 --- /dev/null +++ b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/categorize_error.rs @@ -0,0 +1,5 @@ +use crate::job::job_loop::process_single_job_error::ProcessSingleJobError; + +pub fn categorize_error(stderr_contents: &str) -> Option { + None +} diff --git a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/download_video_file.rs b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/download_video_file.rs new file mode 100644 index 0000000000..344592bd08 --- /dev/null +++ b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/download_video_file.rs @@ -0,0 +1,83 @@ +use std::path::PathBuf; + +use anyhow::anyhow; +use log::{error, warn}; +use sqlx::MySqlPool; +use tempdir::TempDir; + +use buckets::public::media_uploads::original_file::MediaUploadOriginalFilePath; +use cloud_storage::bucket_client::BucketClient; +use jobs_common::job_progress_reporter::job_progress_reporter::JobProgressReporter; +use mysql_queries::payloads::generic_inference_args::videofilter_payload::VideofilterVideoSource; +use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob; +use mysql_queries::queries::media_uploads::get_media_upload_for_inference::get_media_upload_for_inference; +use tokens::tokens::media_uploads::MediaUploadToken; + +use crate::job::job_loop::process_single_job_error::ProcessSingleJobError; +use crate::util::maybe_download_file_from_bucket::{maybe_download_file_from_bucket, MaybeDownloadArgs}; +use crate::util::scoped_temp_dir_creator::ScopedTempDirCreator; + +pub struct VideoFile { + pub filesystem_path: PathBuf, +} + +pub async fn download_video_file( + video_source: &VideofilterVideoSource, + public_bucket_client: &BucketClient, + job_progress_reporter: &mut Box, + job: &AvailableInferenceJob, + temp_dir_creator: &ScopedTempDirCreator, + work_temp_dir: &TempDir, + mysql_pool: &MySqlPool, +) -> Result { + + let bucket_object_path; + + match video_source { + VideofilterVideoSource::F(_media_file_token) => { + // TODO(bt, 2023-09-08): Implement + return Err(ProcessSingleJobError::NotYetImplemented) + } + VideofilterVideoSource::U(media_upload_token) => { + let media_upload_token = MediaUploadToken::new_from_str(media_upload_token); + let media_upload_result = get_media_upload_for_inference( + &media_upload_token, + mysql_pool + ).await; + + let media_upload_result = match media_upload_result { + Ok(Some(result)) => result, + Ok(None) => { + warn!("could not find media upload: {:?}", media_upload_token); + return Err(ProcessSingleJobError::from_anyhow_error( + anyhow!("could not find media upload: {:?}", media_upload_token))) + } + Err(e) => { + error!("could not query media upload: {:?}", e); + return Err(ProcessSingleJobError::from_anyhow_error(e)) + } + }; + + let media_upload_bucket_path = MediaUploadOriginalFilePath::from_object_hash(&media_upload_result.public_bucket_directory_hash); + bucket_object_path = media_upload_bucket_path.to_full_object_pathbuf(); + } + } + + let downloaded_filesystem_path = work_temp_dir.path().join("video.mp4"); + + maybe_download_file_from_bucket(MaybeDownloadArgs { + name_or_description_of_file: "video file", + final_filesystem_file_path: &downloaded_filesystem_path, + bucket_object_path: &bucket_object_path, + bucket_client: public_bucket_client, + job_progress_reporter, + job_progress_update_description: "downloading", + job_id: job.id.0, + scoped_tempdir_creator: &temp_dir_creator, + maybe_existing_file_minimum_size_required: None, + }).await?; + + Ok(VideoFile { + filesystem_path: downloaded_filesystem_path, + }) +} diff --git a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/mod.rs b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/mod.rs new file mode 100644 index 0000000000..152c2840da --- /dev/null +++ b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/mod.rs @@ -0,0 +1,6 @@ +mod process_jobs; +mod validate_job; +mod download_video_file; +mod rerender_inference_command; +pub(crate) mod rerender_dependencies; +mod categorize_error; \ No newline at end of file diff --git a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/process_jobs.rs b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/process_jobs.rs new file mode 100644 index 0000000000..f26de327c6 --- /dev/null +++ b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/process_jobs.rs @@ -0,0 +1,316 @@ +use std::fs::read_to_string; +use std::time::Instant; + +use anyhow::anyhow; +use log::{error, info, warn}; + +use buckets::public::media_files::original_file::MediaFileBucketPath; +use enums::by_table::generic_inference_jobs::inference_result_type::InferenceResultType; +use filesys::check_file_exists::check_file_exists; +use filesys::file_size::file_size; +use filesys::safe_delete_temp_directory::safe_delete_temp_directory; +use filesys::safe_delete_temp_file::safe_delete_temp_file; +use hashing::sha256::sha256_hash_file::sha256_hash_file; +use mimetypes::mimetype_for_file::get_mimetype_for_file; +use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob; +use mysql_queries::queries::media_files::insert_media_file_from_face_animation::{insert_media_file_from_face_animation, InsertArgs}; +use tokens::tokens::users::UserToken; + +use crate::job::job_loop::job_success_result::{JobSuccessResult, ResultEntity}; +use crate::job::job_loop::process_single_job_error::ProcessSingleJobError; +use crate::job::job_types::lipsync::sad_talker::categorize_error::categorize_error; +// use crate::job::job_types::lipsync::sad_talker::categorize_error::categorize_error; +use crate::job::job_types::videofilter::rerender_a_video::download_video_file::download_video_file; +use crate::job::job_types::videofilter::rerender_a_video::rerender_inference_command::InferenceArgs; +use crate::job::job_types::videofilter::rerender_a_video::validate_job::validate_job; +use crate::job_dependencies::JobDependencies; +use crate::util::common_commands::ffmpeg_logo_watermark_command; + +/// The maximum that either width or height can be +const MAX_DIMENSION : u32 = 1500; + +const BUCKET_FILE_PREFIX: &str = "fakeyou_"; +const BUCKET_FILE_EXTENSION: &str = ".mp4"; + +pub struct RerenderProcessJobArgs<'a> { + pub job_dependencies: &'a JobDependencies, + pub job: &'a AvailableInferenceJob, +} + +pub async fn process_job(args: RerenderProcessJobArgs<'_>) -> Result { + let job = args.job; + let deps = args.job_dependencies; + + let mut job_progress_reporter = args.job_dependencies + .clients + .job_progress_reporter + .new_generic_inference(job.inference_job_token.as_str()) + .map_err(|e| ProcessSingleJobError::Other(anyhow!(e)))?; + + let model_dependencies = args + .job_dependencies + .job + .job_specific_dependencies + .maybe_rerender_dependencies + .as_ref() + .ok_or_else(|| ProcessSingleJobError::JobSystemMisconfiguration(Some("missing Rerender dependencies".to_string())))?; + + // ==================== UNPACK + VALIDATE INFERENCE ARGS ==================== // + + let job_args = validate_job(job)?; + + // ==================== TEMP DIR ==================== // + + let work_temp_dir = format!("temp_rerender_inference_{}", job.id.0); + + // NB: TempDir exists until it goes out of scope, at which point it should delete from filesystem. + let work_temp_dir = args.job_dependencies + .fs + .scoped_temp_dir_creator_for_work + .new_tempdir(&work_temp_dir) + .map_err(|e| ProcessSingleJobError::from_io_error(e))?; + + + // ==================== QUERY AND DOWNLOAD FILES ==================== // + + let video_path = download_video_file( + &job_args.video_source, + &args.job_dependencies.buckets.public_bucket_client, + &mut job_progress_reporter, + job, + &args.job_dependencies.fs.scoped_temp_dir_creator_for_work, + &work_temp_dir, + &deps.db.mysql_pool + ).await?; + + info!("Downloaded video file: {:?}", image_path.filesystem_path); + + // ==================== TRANSCODE MEDIA (IF NECESSARY) ==================== // + + let mut usable_video_path = video_path.filesystem_path.clone(); + // + // if let Some((width, height)) = job_args.width.zip(job_args.height) { + // info!("Requested image resize to {}x{} ...", width, height); + // + // let mut width = width.min(MAX_DIMENSION); + // let mut height = height.min(MAX_DIMENSION); + // + // if job_args.enhancer.is_some() { + // // The enhancer will double the size of the image, so we'll downsize the image by half + // // if it's enabled. + // width = width / 2; + // height = height / 2; + // info!("Enhancer will be doubling image size, so cutting frame size to {}x{}.", width, height) + // } + // + // info!("Resizing image to {}x{} ...", width, height); + // + // let result = resize_image( + // &image_path.filesystem_path, + // &work_temp_dir, + // width, + // height + // ); + // + // match result { + // Err(err) => { + // error!("Image resize failure: {:?}", err); + // safe_delete_temp_file(&audio_path.filesystem_path); + // safe_delete_temp_file(&image_path.filesystem_path); + // safe_delete_temp_directory(&work_temp_dir); + // return Err(ProcessSingleJobError::Other(anyhow!("image resize failure: {:?}", err))); + // } + // Ok(resized_image_path) => { + // usable_image_path = resized_image_path; + // } + // } + // } + + info!("Used video file: {:?}", usable_video_path); + + // ==================== SETUP FOR INFERENCE ==================== // + + info!("Ready for Rerender A Video inference..."); + + job_progress_reporter.log_status("running inference") + .map_err(|e| ProcessSingleJobError::Other(e))?; + + let output_video_fs_path = work_temp_dir.path().join("blend.mp4"); + + info!("Running Rerender A Video inference..."); + + info!("Expected output video filename: {:?}", &output_video_fs_path); + + // TODO: Limit output length for non-premium (???) + + let maybe_args = job.maybe_inference_args + .as_ref() + .map(|args| args.args.as_ref()) + .flatten(); + + // ==================== WRITE CONFIG TO DISK ==================== // + + let config_path = work_temp_dir.path().join("config.json"); + + // TODO + + // ==================== RUN INFERENCE SCRIPT ==================== // + + let workdir = work_temp_dir.path().to_path_buf(); + let stderr_output_file = work_temp_dir.path().join("stderr.txt"); + let inference_start_time = Instant::now(); + + let command_exit_status = model_dependencies + .inference_command + .execute_inference(InferenceArgs { + config_file: &config_path, + stderr_output_file: &stderr_output_file, + }); + + let inference_duration = Instant::now().duration_since(inference_start_time); + + info!("Inference took duration to complete: {:?}", &inference_duration); + + if !command_exit_status.is_success() { + error!("Inference failed: {:?}", command_exit_status); + + let mut error = ProcessSingleJobError::Other(anyhow!("CommandExitStatus: {:?}", command_exit_status)); + + if let Ok(contents) = read_to_string(&stderr_output_file) { + warn!("Captured stderr output: {}", contents); + + // match categorize_error(&contents) { + // Some(ProcessSingleJobError::FaceDetectionFailure) => { + // warn!("Face not detected in source image"); + // error = ProcessSingleJobError::FaceDetectionFailure; + // } + // _ => {} + // } + } + + safe_delete_temp_file(&video_path.filesystem_path); + safe_delete_temp_file(&config_path); + safe_delete_temp_file(&output_video_fs_path); + safe_delete_temp_file(&stderr_output_file); + safe_delete_temp_directory(&work_temp_dir); + + return Err(error); + } + + // ==================== CHECK NON-WATERMARKED RESULT ==================== // + + info!("Checking that output file exists: {:?} ...", output_video_fs_path); + + check_file_exists(&output_video_fs_path).map_err(|e| ProcessSingleJobError::Other(e))?; + + // ==================== OPTIONAL WATERMARK ==================== // + + let mut finished_file = output_video_fs_path.clone(); + + // ==================== CHECK ALL FILES EXIST AND GET METADATA ==================== // + + info!("Checking that output watermark file exists: {:?} ...", finished_file); + check_file_exists(&finished_file).map_err(|e| ProcessSingleJobError::Other(e))?; + + info!("Interrogating result file size ..."); + + let file_size_bytes = file_size(&finished_file) + .map_err(|err| ProcessSingleJobError::Other(err))?; + + info!("Interrogating result mimetype ..."); + + let mimetype = get_mimetype_for_file(&finished_file) + .map_err(|err| ProcessSingleJobError::from_io_error(err))? + .map(|mime| mime.to_string()) + .ok_or(ProcessSingleJobError::Other(anyhow!("Mimetype could not be determined")))?; + + info!("Calculating sha256..."); + + let file_checksum = sha256_hash_file(&finished_file) + .map_err(|err| { + ProcessSingleJobError::Other(anyhow!("Error hashing file: {:?}", err)) + })?; + + // ==================== UPLOAD AUDIO TO BUCKET ==================== // + + job_progress_reporter.log_status("uploading result") + .map_err(|e| ProcessSingleJobError::Other(e))?; + + let result_bucket_location = MediaFileBucketPath::generate_new( + Some(BUCKET_FILE_PREFIX), + Some(BUCKET_FILE_EXTENSION)); + + let result_bucket_object_pathbuf = result_bucket_location.to_full_object_pathbuf(); + + info!("Audio destination bucket path: {:?}", &result_bucket_object_pathbuf); + + info!("Uploading media ..."); + + args.job_dependencies.buckets.public_bucket_client.upload_filename_with_content_type( + &result_bucket_object_pathbuf, + &finished_file, + &mimetype) // TODO: We should check the mimetype to make sure bad payloads can't get uploaded + .await + .map_err(|e| ProcessSingleJobError::Other(e))?; + + // ==================== DELETE TEMP FILES ==================== // + + safe_delete_temp_file(&video_path.filesystem_path); + safe_delete_temp_file(&config_path); + safe_delete_temp_file(&output_video_fs_path); + safe_delete_temp_file(&stderr_output_file); + safe_delete_temp_directory(&work_temp_dir); + + // NB: We should be using a tempdir, but to make absolutely certain we don't overflow the disk... + safe_delete_temp_directory(&work_temp_dir); + + // ==================== SAVE RECORDS ==================== // + + info!("Saving SadTalker result (media_files table record) ..."); + + let (media_file_token, id) = insert_media_file_from_face_animation(InsertArgs { + pool: &args.job_dependencies.db.mysql_pool, + job: &job, + maybe_mime_type: Some(&mimetype), + file_size_bytes, + sha256_checksum: &file_checksum, + public_bucket_directory_hash: result_bucket_location.get_object_hash(), + maybe_public_bucket_prefix: Some(BUCKET_FILE_PREFIX), + maybe_public_bucket_extension: Some(BUCKET_FILE_EXTENSION), + is_on_prem: args.job_dependencies.job.info.container.is_on_prem, + worker_hostname: &args.job_dependencies.job.info.container.hostname, + worker_cluster: &args.job_dependencies.job.info.container.cluster_name, + }) + .await + .map_err(|e| ProcessSingleJobError::Other(e))?; + + info!("SadTalker Done."); + + // TODO: Update upstream to be strongly typed + let maybe_user_token = job.maybe_creator_user_token.as_deref() + .map(|token| UserToken::new_from_str(token)); + + args.job_dependencies.clients.firehose_publisher.lipsync_animation_finished( + maybe_user_token.as_ref(), + &job.inference_job_token, + media_file_token.as_str()) + .await + .map_err(|e| { + error!("error publishing event: {:?}", e); + ProcessSingleJobError::Other(anyhow!("error publishing event")) + })?; + + job_progress_reporter.log_status("done") + .map_err(|e| ProcessSingleJobError::Other(e))?; + + info!("Job {:?} complete success! Downloaded, ran inference, and uploaded. Saved model record: {}, Result Token: {}", + job.id, id, &media_file_token); + + Ok(JobSuccessResult { + maybe_result_entity: Some(ResultEntity { + entity_type: InferenceResultType::MediaFile, + entity_token: media_file_token.to_string(), + }), + inference_duration, + }) +} diff --git a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/rerender_dependencies.rs b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/rerender_dependencies.rs new file mode 100644 index 0000000000..c50fe62ece --- /dev/null +++ b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/rerender_dependencies.rs @@ -0,0 +1,15 @@ +use errors::AnyhowResult; + +use crate::job::job_types::videofilter::rerender_a_video::rerender_inference_command::RerenderInferenceCommand; + +pub struct RerenderDependencies { + pub inference_command: RerenderInferenceCommand, +} + +impl RerenderDependencies { + pub fn setup() -> AnyhowResult { + Ok(Self { + inference_command: RerenderInferenceCommand::from_env()?, + }) + } +} diff --git a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/rerender_inference_command.rs b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/rerender_inference_command.rs new file mode 100644 index 0000000000..2c221e2b28 --- /dev/null +++ b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/rerender_inference_command.rs @@ -0,0 +1,233 @@ +use std::collections::HashSet; +use std::env; +use std::ffi::OsString; +use std::fs::File; +use std::path::{Path, PathBuf}; +use std::time::Duration; + +use anyhow::anyhow; +use log::info; +use once_cell::sync::Lazy; +use subprocess::{Popen, PopenConfig, Redirection}; + +use errors::AnyhowResult; +use filesys::path_to_string::path_to_string; +use subprocess_common::docker_options::{DockerFilesystemMount, DockerGpu, DockerOptions}; + +use crate::job::job_loop::command_exit_status::CommandExitStatus; + +// These environment vars are not copied over to the subprocess +// TODO/FIXME(bt, 2023-05-28): This is horrific security! +static IGNORED_ENVIRONMENT_VARS : Lazy> = Lazy::new(|| { + let env_var_names= [ + "MYSQL_URL", + "ACCESS_KEY", + "SECRET_KEY", + "NEWRELIC_API_KEY", + ]; + + env_var_names.iter() + .map(|value| value.to_string()) + .collect::>() +}); + +#[derive(Clone)] +pub struct RerenderInferenceCommand { + /// Where the code lives + rerender_root_code_directory: PathBuf, + + /// A single executable script or a much larger bash command. + executable_or_command: ExecutableOrCommand, + + /// Config file to use + config_path: PathBuf, + + /// eg. `source python/bin/activate` + maybe_virtual_env_activation_command: Option, + + /// If this is run under Docker (eg. in development), these are the options. + maybe_docker_options: Option, + + /// If the execution should be ended after a certain point. + maybe_execution_timeout: Option, + +} + +#[derive(Clone)] +pub enum ExecutableOrCommand { + /// Eg. `inference.py` + Executable(PathBuf), + + /// Eg. `python3 inference.py` + Command(String), +} + +pub struct InferenceArgs<'s, P: AsRef> { + pub config_file: P, + pub stderr_output_file: &'s Path, +} + +impl RerenderInferenceCommand { + pub fn new>( + rerender_root_code_directory: PathBuf, + executable_or_command: ExecutableOrCommand, + config_path: PathBuf, + maybe_virtual_env_activation_command: Option, + maybe_docker_options: Option, + maybe_execution_timeout: Option, + ) -> Self { + Self { + rerender_root_code_directory: rerender_root_code_directory.as_ref().to_path_buf(), + executable_or_command, + config_path: config_path.as_ref().to_path_buf(), + maybe_virtual_env_activation_command: maybe_virtual_env_activation_command.map(|s| s.to_string()), + maybe_docker_options, + maybe_execution_timeout, + } + } + + pub fn from_env() -> AnyhowResult { + let rerender_root_code_directory = easyenv::get_env_pathbuf_required( + "RERENDER_INFERENCE_ROOT_DIRECTORY")?; + + let config_path = easyenv::get_env_pathbuf_required( + "RERENDER_INFERENCE_CONFIG_PATH")?; + + let maybe_virtual_env_activation_command = easyenv::get_env_string_optional( + "RERENDER_INFERENCE_MAYBE_VENV_COMMAND"); + + let maybe_execution_timeout = + easyenv::get_env_duration_seconds_optional("RERENDER_TIMEOUT_SECONDS"); + + let maybe_docker_options = easyenv::get_env_string_optional( + "RERENDER_INFERENCE_MAYBE_DOCKER_IMAGE") + .map(|image_name| { + DockerOptions { + image_name, + maybe_bind_mount: Some(DockerFilesystemMount::tmp_to_tmp()), + maybe_environment_variables: None, + maybe_gpu: Some(DockerGpu::All), + } + }); + + Ok(Self { + rerender_root_code_directory, + executable_or_command, + config_path, + maybe_virtual_env_activation_command, + maybe_docker_options, + maybe_execution_timeout, + }) + } + + pub fn execute_inference>( + &self, + args: InferenceArgs

, + ) -> CommandExitStatus { + match self.do_execute_inference(args) { + Ok(exit_status) => exit_status, + Err(error) => CommandExitStatus::FailureWithReason { reason: format!("error: {:?}", error) }, + } + } + + fn do_execute_inference>( + &self, + args: InferenceArgs

, + ) -> AnyhowResult { + + let mut command = String::new(); + command.push_str(&format!("cd {}", path_to_string(&self.rerender_root_code_directory))); + + if let Some(venv_command) = self.maybe_virtual_env_activation_command.as_deref() { + command.push_str(" && "); + command.push_str(venv_command); + command.push_str(" "); + } + + command.push_str(" && "); + + match self.executable_or_command { + ExecutableOrCommand::Executable(ref executable) => { + command.push_str(&path_to_string(executable)); + command.push_str(" "); + } + ExecutableOrCommand::Command(ref cmd) => { + command.push_str(cmd); + command.push_str(" "); + } + } + + // ===== Begin Python Args ===== + + command.push_str(" --cfg "); + command.push_str(&path_to_string(args.config_file.as_ref())); + + // ===== End Python Args ===== + + if let Some(docker_options) = self.maybe_docker_options.as_ref() { + command = docker_options.to_command_string(&command); + } + + info!("Command: {:?}", command); + + let command_parts = [ + "bash", + "-c", + &command + ]; + + let mut env_vars = Vec::new(); + + // Copy all environment variables from the parent process. + // This is necessary to send all the kubernetes settings for Nvidia / CUDA. + for (env_key, env_value) in env::vars() { + if IGNORED_ENVIRONMENT_VARS.contains(&env_key) { + continue; + } + env_vars.push(( + OsString::from(env_key), + OsString::from(env_value), + )); + } + + let mut config = PopenConfig::default(); + + info!("stderr will be written to file: {:?}", args.stderr_output_file.as_ref()); + + let stderr_file = File::create(&args.stderr_output_file)?; + config.stderr = Redirection::File(stderr_file); + + if !env_vars.is_empty() { + config.env = Some(env_vars); + } + + let mut p = Popen::create(&command_parts, config)?; + + info!("Subprocess PID: {:?}", p.pid()); + + match self.maybe_execution_timeout { + None => { + let exit_status = p.wait()?; + info!("Subprocess exit status: {:?}", exit_status); + Ok(CommandExitStatus::from_exit_status(exit_status)) + } + Some(timeout) => { + info!("Executing with timeout: {:?}", &timeout); + let exit_status = p.wait_timeout(timeout.clone())?; + + match exit_status { + None => { + // NB: If the program didn't successfully terminate, kill it. + info!("Subprocess didn't end after timeout: {:?}; terminating...", &timeout); + let _r = p.terminate()?; + Ok(CommandExitStatus::Timeout) + } + Some(exit_status) => { + info!("Subprocess timed wait exit status: {:?}", exit_status); + Ok(CommandExitStatus::from_exit_status(exit_status)) + } + } + } + } + } +} diff --git a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/validate_job.rs b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/validate_job.rs new file mode 100644 index 0000000000..127a601f30 --- /dev/null +++ b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/validate_job.rs @@ -0,0 +1,85 @@ +use anyhow::anyhow; + +use mysql_queries::payloads::generic_inference_args::generic_inference_args::{InferenceCategoryAbbreviated, PolymorphicInferenceArgs}; +use mysql_queries::payloads::generic_inference_args::videofilter_payload::{VideofilterVideoSource}; +use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob; + +use crate::job::job_loop::process_single_job_error::ProcessSingleJobError; + +pub struct JobArgs<'a> { + pub video_source: &'a VideofilterVideoSource, + pub sd_model: &'a str, +} + +pub fn validate_job(job: &AvailableInferenceJob) -> Result { + let inference_args = job.maybe_inference_args + .as_ref() + .map(|args| args.args.as_ref()) + .flatten(); + + let inference_category = job.maybe_inference_args + .as_ref() + .map(|args| args.inference_category) + .flatten(); + + match inference_category { + Some(InferenceCategoryAbbreviated::RerenderAVideo) => {}, // Valid + Some(category) => { + return Err(ProcessSingleJobError::from_anyhow_error(anyhow!("wrong inference category for job: {:?}", category))); + }, + None => { + return Err(ProcessSingleJobError::from_anyhow_error(anyhow!("no inference category for job!"))); + } + }; + + let inference_args = match inference_args { + Some(args) => args, + None => { + return Err(ProcessSingleJobError::from_anyhow_error(anyhow!("no inference args for job!"))); + } + }; + + let inference_args = match inference_args { + PolymorphicInferenceArgs::Rr(inference_args) => inference_args, + _ => { + return Err(ProcessSingleJobError::from_anyhow_error(anyhow!("wrong inner args for job!"))); + } + }; + + let video_source = match &inference_args.maybe_video_source { + Some(args) => args, + None => { + return Err(ProcessSingleJobError::from_anyhow_error(anyhow!("no video source!"))); + } + }; + + let sd_model = match &inference_args.sd_model { + Some(args) => args, + None => { + return Err(ProcessSingleJobError::from_anyhow_error(anyhow!("no sd model!"))); + } + }; + + + // let preprocess = match inference_args.maybe_preprocess { + // None => Some("full".to_string()), + // Some(Preprocess::F) => Some("full".to_string()), + // Some(Preprocess::EF) => Some("extfull".to_string()), + // Some(Preprocess::C) => Some("crop".to_string()), + // Some(Preprocess::EC) => Some("extcrop".to_string()), + // }; + // + // let enhancer = match inference_args.maybe_face_enhancer { + // None => None, + // Some(FaceEnhancer::G) => Some("gfpgan".to_string()), + // Some(FaceEnhancer::R) => Some("RestoreFormer".to_string()), + // }; + // + // let mut width = inference_args.maybe_resize_width; + // let mut height = inference_args.maybe_resize_height; + + Ok(JobArgs { + video_source, + sd_model, + }) +} diff --git a/crates/service/job/inference_job/src/job_specific_dependencies.rs b/crates/service/job/inference_job/src/job_specific_dependencies.rs index ddd313a46a..a863b3872c 100644 --- a/crates/service/job/inference_job/src/job_specific_dependencies.rs +++ b/crates/service/job/inference_job/src/job_specific_dependencies.rs @@ -7,6 +7,7 @@ use crate::job::job_types::tts::vall_e_x::vall_e_x_dependencies::VallExDependenc use crate::job::job_types::tts::vits::vits_dependencies::VitsDependencies; use crate::job::job_types::vc::rvc_v2::rvc_v2_dependencies::RvcV2Dependencies; use crate::job::job_types::vc::so_vits_svc::svc_dependencies::SvcDependencies; +use crate::job::job_types::videofilter::rerender_a_video::rerender_dependencies::RerenderDependencies; use crate::util::scoped_execution::ScopedExecution; pub struct JobSpecificDependencies { @@ -16,6 +17,7 @@ pub struct JobSpecificDependencies { pub maybe_tacotron2_dependencies: Option, pub maybe_vall_e_x_dependencies: Option, pub maybe_vits_dependencies: Option, + pub maybe_rerender_dependencies: Option, } impl JobSpecificDependencies { @@ -27,6 +29,7 @@ impl JobSpecificDependencies { let mut maybe_tacotron2_dependencies = None; let mut maybe_vall_e_x_dependencies = None; let mut maybe_vits_dependencies = None; + let mut maybe_rerender_dependencies = None; if scoped_execution.can_run_job(InferenceModelType::RvcV2) { print_with_space("Setting RVCv2 dependencies..."); @@ -58,6 +61,11 @@ impl JobSpecificDependencies { maybe_vits_dependencies = Some(VitsDependencies::setup()?); } + if scoped_execution.can_run_job(InferenceModelType::RerenderAVideo) { + print_with_space("Setting Rerender dependencies..."); + maybe_rerender_dependencies = Some(RerenderDependencies::setup()?); + } + Ok(JobSpecificDependencies { maybe_rvc_v2_dependencies, maybe_sad_talker_dependencies, @@ -65,6 +73,7 @@ impl JobSpecificDependencies { maybe_tacotron2_dependencies, maybe_vall_e_x_dependencies, maybe_vits_dependencies, + maybe_rerender_dependencies, }) } } diff --git a/crates/service/web/storyteller_web/src/routes.rs b/crates/service/web/storyteller_web/src/routes.rs index 9bc7775457..f612d034f7 100644 --- a/crates/service/web/storyteller_web/src/routes.rs +++ b/crates/service/web/storyteller_web/src/routes.rs @@ -206,6 +206,7 @@ pub fn add_routes (app: App, server_environment: ServerEnvironment) -> let mut app = RouteBuilder::from_app(app) .add_post("/v1/animation/face_animation/create", enqueue_lipsync_animation_handler) + .add_post("/v1/animation/rerender/create", enqueue_rerender_animation_handler) .into_app(); // ==================== "Generic" Inference ==================== From 43030402ca20f41b72ff73b9f22b2c33e3b371fb Mon Sep 17 00:00:00 2001 From: salt Date: Tue, 12 Dec 2023 14:50:50 -0800 Subject: [PATCH 019/124] update --- Cargo.lock | 1 + .../inference_model_type.rs | 3 +- .../generic_inference_args.rs | 2 +- .../videofilter_payload.rs | 2 +- .../web/get_inference_job_status.rs | 2 + .../src/job/job_loop/process_single_job.rs | 3 + .../job/job_types/vc/rvc_v2/process_job.rs | 2 + .../job_types/vc/so_vits_svc/process_job.rs | 2 + .../src/job/job_types/videofilter/mod.rs | 3 +- .../videofilter/process_single_vf_job.rs | 63 +++++ .../videofilter/rerender_a_video/mod.rs | 2 +- .../rerender_a_video/process_jobs.rs | 2 +- .../rerender_a_video/validate_job.rs | 2 +- .../traits/internal_session_cache_purge.rs | 1 + crates/service/web/storyteller_web/Cargo.toml | 1 + .../storyteller_web/src/configs/plans/plan.rs | 19 ++ .../animation/enqueue_rerender_animation.rs | 237 ++++++++++++++++++ .../http_server/endpoints/animation/mod.rs | 3 +- .../inference_job/get_inference_job_status.rs | 8 + .../service/web/storyteller_web/src/routes.rs | 1 + 20 files changed, 351 insertions(+), 8 deletions(-) create mode 100644 crates/service/job/inference_job/src/job/job_types/videofilter/process_single_vf_job.rs create mode 100644 crates/service/web/storyteller_web/src/http_server/endpoints/animation/enqueue_rerender_animation.rs diff --git a/Cargo.lock b/Cargo.lock index d8fddc06d1..215225d64d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6025,6 +6025,7 @@ dependencies = [ "hex", "hmac 0.10.1", "hostname", + "http", "http_server_common", "hyper", "infer 0.5.0", diff --git a/crates/_types/enums/src/by_table/generic_inference_jobs/inference_model_type.rs b/crates/_types/enums/src/by_table/generic_inference_jobs/inference_model_type.rs index 5401430bd1..0a30156539 100644 --- a/crates/_types/enums/src/by_table/generic_inference_jobs/inference_model_type.rs +++ b/crates/_types/enums/src/by_table/generic_inference_jobs/inference_model_type.rs @@ -48,7 +48,8 @@ impl InferenceModelType { Self::SoVitsSvc => "so_vits_svc", Self::Tacotron2 => "tacotron2", Self::Vits => "vits", - Self::VallEX => "vall_e_x" + Self::VallEX => "vall_e_x", + Self::RerenderAVideo => "rerender_a_video", } } diff --git a/crates/lib/mysql_queries/src/payloads/generic_inference_args/generic_inference_args.rs b/crates/lib/mysql_queries/src/payloads/generic_inference_args/generic_inference_args.rs index 7ba7b0b3ef..f34a4469c3 100644 --- a/crates/lib/mysql_queries/src/payloads/generic_inference_args/generic_inference_args.rs +++ b/crates/lib/mysql_queries/src/payloads/generic_inference_args/generic_inference_args.rs @@ -3,7 +3,7 @@ use errors::AnyhowResult; use crate::payloads::generic_inference_args::lipsync_payload::LipsyncArgs; use crate::payloads::generic_inference_args::tts_payload::TTSArgs; -use crate::payloads::generic_inference_args::videofilter_payload::VideofilterVideoSource; +use crate::payloads::generic_inference_args::videofilter_payload::{RerenderArgs}; /// Used to encode extra state for the `generic_inference_jobs` table. diff --git a/crates/lib/mysql_queries/src/payloads/generic_inference_args/videofilter_payload.rs b/crates/lib/mysql_queries/src/payloads/generic_inference_args/videofilter_payload.rs index 85335cde79..12d316933f 100644 --- a/crates/lib/mysql_queries/src/payloads/generic_inference_args/videofilter_payload.rs +++ b/crates/lib/mysql_queries/src/payloads/generic_inference_args/videofilter_payload.rs @@ -32,5 +32,5 @@ pub struct RerenderArgs { #[serde(rename = "sd")] #[serde(skip_serializing_if = "Option::is_none")] - pub sd_model: String, + pub maybe_sd_model: Option, } diff --git a/crates/lib/mysql_queries/src/queries/generic_inference/web/get_inference_job_status.rs b/crates/lib/mysql_queries/src/queries/generic_inference/web/get_inference_job_status.rs index a59fd2e5d2..247eb2b9c0 100644 --- a/crates/lib/mysql_queries/src/queries/generic_inference/web/get_inference_job_status.rs +++ b/crates/lib/mysql_queries/src/queries/generic_inference/web/get_inference_job_status.rs @@ -177,6 +177,7 @@ fn raw_record_to_public_result(record: RawGenericInferenceJobStatus) -> GenericI InferenceCategory::LipsyncAnimation => Some("lipsync animation"), InferenceCategory::TextToSpeech => record.maybe_tts_model_title.as_deref(), InferenceCategory::VoiceConversion => record.maybe_voice_conversion_model_title.as_deref(), + InferenceCategory::RerenderAVideo => Some("rerender animation"), }; // NB: A bit of a hack. We store TTS results with a full path. @@ -185,6 +186,7 @@ fn raw_record_to_public_result(record: RawGenericInferenceJobStatus) -> GenericI InferenceCategory::LipsyncAnimation => (true, record.maybe_media_file_public_bucket_directory_hash.as_deref()), InferenceCategory::TextToSpeech => (false, record.maybe_tts_public_bucket_path.as_deref()), InferenceCategory::VoiceConversion => (true, record.maybe_voice_conversion_public_bucket_hash.as_deref()), + InferenceCategory::RerenderAVideo => (true, record.maybe_media_file_public_bucket_directory_hash.as_deref()), }; // NB: We've moved voice conversion out of their own table and into media_files diff --git a/crates/service/job/inference_job/src/job/job_loop/process_single_job.rs b/crates/service/job/inference_job/src/job/job_loop/process_single_job.rs index 2d8f04efa9..6dc5a4f7d4 100644 --- a/crates/service/job/inference_job/src/job/job_loop/process_single_job.rs +++ b/crates/service/job/inference_job/src/job/job_loop/process_single_job.rs @@ -182,6 +182,9 @@ async fn do_process_single_job( InferenceCategory::VoiceConversion => { process_single_vc_job(job_dependencies, job).await? } + InferenceCategory::RerenderAVideo => { + process_single_rerender_job(job_dependencies, job).await? + } }; let maybe_entity_type = job_success_result.maybe_result_entity diff --git a/crates/service/job/inference_job/src/job/job_types/vc/rvc_v2/process_job.rs b/crates/service/job/inference_job/src/job/job_types/vc/rvc_v2/process_job.rs index 74496b6abc..082dd95eac 100644 --- a/crates/service/job/inference_job/src/job/job_types/vc/rvc_v2/process_job.rs +++ b/crates/service/job/inference_job/src/job/job_types/vc/rvc_v2/process_job.rs @@ -239,6 +239,7 @@ pub async fn process_job(args: RvcV2ProcessJobArgs<'_>) -> Result None, PolymorphicInferenceArgs::La(_) => None, PolymorphicInferenceArgs::Vc { override_f0_method, .. } => *override_f0_method, + PolymorphicInferenceArgs::Rr(_) => None, }) .flatten(); @@ -247,6 +248,7 @@ pub async fn process_job(args: RvcV2ProcessJobArgs<'_>) -> Result None, PolymorphicInferenceArgs::La(_) => None, PolymorphicInferenceArgs::Vc { transpose, .. } => *transpose, + PolymorphicInferenceArgs::Rr(_) => None, }) .flatten(); diff --git a/crates/service/job/inference_job/src/job/job_types/vc/so_vits_svc/process_job.rs b/crates/service/job/inference_job/src/job/job_types/vc/so_vits_svc/process_job.rs index f5d7fa1b89..69337d467f 100644 --- a/crates/service/job/inference_job/src/job/job_types/vc/so_vits_svc/process_job.rs +++ b/crates/service/job/inference_job/src/job/job_types/vc/so_vits_svc/process_job.rs @@ -168,6 +168,7 @@ pub async fn process_job(args: SoVitsSvcProcessJobArgs<'_>) -> Result None, PolymorphicInferenceArgs::La(_) => None, PolymorphicInferenceArgs::Vc { auto_predict_f0, .. } => *auto_predict_f0, + PolymorphicInferenceArgs::Rr(_) => None, }) .flatten() .unwrap_or(false); @@ -177,6 +178,7 @@ pub async fn process_job(args: SoVitsSvcProcessJobArgs<'_>) -> Result None, PolymorphicInferenceArgs::La(_) => None, PolymorphicInferenceArgs::Vc { transpose, .. } => *transpose, + PolymorphicInferenceArgs::Rr(_) => None, }) .flatten(); diff --git a/crates/service/job/inference_job/src/job/job_types/videofilter/mod.rs b/crates/service/job/inference_job/src/job/job_types/videofilter/mod.rs index b8f301c73d..7f70f41199 100644 --- a/crates/service/job/inference_job/src/job/job_types/videofilter/mod.rs +++ b/crates/service/job/inference_job/src/job/job_types/videofilter/mod.rs @@ -1 +1,2 @@ -pub(crate) mod rerender_a_video; \ No newline at end of file +pub(crate) mod rerender_a_video; +mod process_single_vf_job; diff --git a/crates/service/job/inference_job/src/job/job_types/videofilter/process_single_vf_job.rs b/crates/service/job/inference_job/src/job/job_types/videofilter/process_single_vf_job.rs new file mode 100644 index 0000000000..eee4f2cd8d --- /dev/null +++ b/crates/service/job/inference_job/src/job/job_types/videofilter/process_single_vf_job.rs @@ -0,0 +1,63 @@ +use std::time::Duration; + +use anyhow::anyhow; +use log::{error, info}; + +use enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType; +use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob; +use mysql_queries::queries::media_uploads::get_media_upload_for_inference::get_media_upload_for_inference; +use mysql_queries::queries::voice_conversion::inference::get_voice_conversion_model_for_inference::get_voice_conversion_model_for_inference; +use tokens::tokens::media_uploads::MediaUploadToken; + +use crate::job::job_loop::job_success_result::JobSuccessResult; +use crate::job::job_loop::process_single_job_error::ProcessSingleJobError; +use crate::job::job_types::vc::{rvc_v2, so_vits_svc}; +use crate::job::job_types::vc::rvc_v2::process_job::RvcV2ProcessJobArgs; +use crate::job::job_types::vc::so_vits_svc::process_job::SoVitsSvcProcessJobArgs; +use crate::job_dependencies::JobDependencies; + +pub async fn process_single_rr_job(job_dependencies: &JobDependencies, job: &AvailableInferenceJob) -> Result { + let maybe_media_upload_token = job.maybe_input_source_token + .as_deref() + .map(|token| MediaUploadToken::new_from_str(token)); + + let media_upload_token = match maybe_media_upload_token { + None => return Err(ProcessSingleJobError::Other(anyhow!("no associated media upload for vc job: {:?}", job.inference_job_token))), + Some(token) => token, + }; + + let maybe_media_upload_result = + get_media_upload_for_inference(&media_upload_token, &job_dependencies.db.mysql_pool).await; + + let media_upload = match maybe_media_upload_result { + Ok(Some(media_upload)) => media_upload, + Ok(None) => { + error!("no media upload record found for token: {:?}", media_upload_token); + return Err(ProcessSingleJobError::Other(anyhow!("no media upload record found for token: {:?}", media_upload_token))); + }, + Err(err) => { + error!("error fetching media upload record from db: {:?}", err); + return Err(ProcessSingleJobError::Other(err)); + }, + }; + + info!("Source media upload file size (bytes): {}", &media_upload.original_file_size_bytes); + info!("Source media upload duration (millis): {}", &media_upload.original_duration_millis); + info!("Source media upload duration (seconds): {}", (media_upload.original_duration_millis as f32 / 1000.0)); + + + + let job_success_result = match vc_model.model_type { + VoiceConversionModelType::RvcV2 => { + rvc_v2::process_job::process_job(RvcV2ProcessJobArgs { + job_dependencies, + job, + vc_model: &vc_model, + media_upload_token: &media_upload_token, + media_upload: &media_upload, + }).await? + } + }; + + Ok(job_success_result) +} diff --git a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/mod.rs b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/mod.rs index 152c2840da..711397cfb1 100644 --- a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/mod.rs +++ b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/mod.rs @@ -3,4 +3,4 @@ mod validate_job; mod download_video_file; mod rerender_inference_command; pub(crate) mod rerender_dependencies; -mod categorize_error; \ No newline at end of file +mod categorize_error; diff --git a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/process_jobs.rs b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/process_jobs.rs index f26de327c6..affec1aee3 100644 --- a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/process_jobs.rs +++ b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/process_jobs.rs @@ -83,7 +83,7 @@ pub async fn process_job(args: RerenderProcessJobArgs<'_>) -> Result Result args, None => { return Err(ProcessSingleJobError::from_anyhow_error(anyhow!("no sd model!"))); diff --git a/crates/service/plugins/billing/src/stripe/traits/internal_session_cache_purge.rs b/crates/service/plugins/billing/src/stripe/traits/internal_session_cache_purge.rs index d125c53d7f..69abd86b95 100644 --- a/crates/service/plugins/billing/src/stripe/traits/internal_session_cache_purge.rs +++ b/crates/service/plugins/billing/src/stripe/traits/internal_session_cache_purge.rs @@ -1,4 +1,5 @@ use actix_web::HttpRequest; +use mockall::automock; /// Allows us to purge session caches that might keep stale premium plan/billing data around #[cfg_attr(test, automock)] diff --git a/crates/service/web/storyteller_web/Cargo.toml b/crates/service/web/storyteller_web/Cargo.toml index df7cab336c..f015262c17 100644 --- a/crates/service/web/storyteller_web/Cargo.toml +++ b/crates/service/web/storyteller_web/Cargo.toml @@ -164,6 +164,7 @@ pulldown-cmark = "0.9.3" async-trait = "0.1.58" utoipa = { version = "4", features = ["actix_extras"] } utoipa-swagger-ui = { version = "5", features = ["actix-web"] } +http = "0.2.11" [build-dependencies] # NB: Only using diesel for migrations support diff --git a/crates/service/web/storyteller_web/src/configs/plans/plan.rs b/crates/service/web/storyteller_web/src/configs/plans/plan.rs index 67dd178cc1..80d100a9fe 100644 --- a/crates/service/web/storyteller_web/src/configs/plans/plan.rs +++ b/crates/service/web/storyteller_web/src/configs/plans/plan.rs @@ -49,6 +49,9 @@ pub struct Plan { can_remove_visual_watermarks: bool, + // ========== Features for Videofilters ========== + rerender_requires_frontend_keepalive: bool, + // ========== Features for TTS ========== tts_base_priority_level: u8, @@ -91,6 +94,7 @@ impl Plan { is_development_plan: builder.is_development_plan, is_synthetic_plan: builder.is_synthetic_plan, lipsync_requires_frontend_keepalive: builder.lipsync_requires_frontend_keepalive, + rerender_requires_frontend_keepalive: builder.rerender_requires_frontend_keepalive, can_remove_visual_watermarks: builder.can_remove_visual_watermarks, tts_base_priority_level: builder.tts_base_priority_level, tts_max_duration: builder.tts_max_duration, @@ -146,6 +150,10 @@ impl Plan { self.lipsync_requires_frontend_keepalive } + pub fn rerender_requires_frontent_keepalive(&self) -> bool { + self.rerender_requires_frontend_keepalive + } + pub fn can_remove_visual_watermarks(&self) -> bool { self.can_remove_visual_watermarks } @@ -192,6 +200,9 @@ pub struct PlanBuilder { can_remove_visual_watermarks: bool, + // ========== Features for Videofilters ========== + rerender_requires_frontend_keepalive: bool, + // ========== Features for TTS ========== tts_base_priority_level: u8, @@ -239,6 +250,9 @@ impl PlanBuilder { lipsync_requires_frontend_keepalive: true, can_remove_visual_watermarks: false, + // Videofilters + rerender_requires_frontend_keepalive: true, + // TTS tts_base_priority_level : TTS_DEFAULT_PRIORITY_LEVEL, tts_max_duration: Duration::seconds(TTS_DEFAULT_DURATION_SECONDS), @@ -304,6 +318,11 @@ impl PlanBuilder { self } + pub fn rerender_requires_frontend_keepalive(mut self, value: bool) -> Self { + self.rerender_requires_frontend_keepalive = value; + self + } + pub fn can_remove_visual_watermarks(mut self, value: bool) -> Self { self.can_remove_visual_watermarks = value; self diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/animation/enqueue_rerender_animation.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/animation/enqueue_rerender_animation.rs new file mode 100644 index 0000000000..1519e5332b --- /dev/null +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/animation/enqueue_rerender_animation.rs @@ -0,0 +1,237 @@ +// NB: Incrementally getting rid of build warnings... +#![forbid(unused_imports)] +#![forbid(unused_mut)] +#![forbid(unused_variables)] + +use std::sync::Arc; + +use actix_web::{HttpRequest, HttpResponse, web}; +use actix_web::error::ResponseError; +use actix_web::http::StatusCode; +use log::{info, warn}; + +use enums::by_table::generic_inference_jobs::inference_category::InferenceCategory; +use enums::by_table::generic_inference_jobs::inference_model_type::InferenceModelType; +use enums::common::visibility::Visibility; +use http_server_common::request::get_request_header_optional::get_request_header_optional; +use http_server_common::request::get_request_ip::get_request_ip; +use mysql_queries::payloads::generic_inference_args::generic_inference_args::{GenericInferenceArgs, InferenceCategoryAbbreviated, PolymorphicInferenceArgs}; +use mysql_queries::payloads::generic_inference_args::videofilter_payload::{RerenderArgs, VideofilterVideoSource}; +use mysql_queries::queries::generic_inference::web::insert_generic_inference_job::{insert_generic_inference_job, InsertGenericInferenceArgs}; +use tokens::tokens::generic_inference_jobs::InferenceJobToken; +use tokens::tokens::media_files::MediaFileToken; +use tokens::tokens::media_uploads::MediaUploadToken; +use tokens::tokens::users::UserToken; + +use crate::configs::plans::get_correct_plan_for_session::get_correct_plan_for_session; +use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; +use crate::server_state::ServerState; + +/// Debug requests can get routed to special "debug-only" workers, which can +/// be used to trial new code, run debugging, etc. +const DEBUG_HEADER_NAME : &str = "enable-debug-mode"; + +/// The routing tag header can send workloads to particular k8s hosts. +/// This is useful for catching the live logs or intercepting the job. +const ROUTING_TAG_HEADER_NAME : &str = "routing-tag"; + +#[derive(Deserialize)] +pub struct EnqueueRerenderAnimationRequest { + uuid_idempotency_token: String, + + video_source: VideoSource, + sd_model: String, + creator_set_visibility: Option, +} + +/// Treated as an enum. Only one of these may be set. +#[derive(Deserialize)] +pub struct VideoSource { + maybe_media_file_token: Option, + maybe_media_upload_token: Option, +} + +#[derive(Serialize)] +pub struct EnqueueRerenderAnimationSuccessResponse { + pub success: bool, + pub inference_job_token: InferenceJobToken, +} + +#[derive(Debug)] +pub enum EnqueueRerenderAnimationError { + BadInput(String), + NotAuthorized, + ServerError, + RateLimited, +} + +impl ResponseError for EnqueueRerenderAnimationError { + fn status_code(&self) -> StatusCode { + match *self { + EnqueueRerenderAnimationError::BadInput(_) => StatusCode::BAD_REQUEST, + EnqueueRerenderAnimationError::NotAuthorized => StatusCode::UNAUTHORIZED, + EnqueueRerenderAnimationError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, + EnqueueRerenderAnimationError::RateLimited => StatusCode::TOO_MANY_REQUESTS, + } + } + + fn error_response(&self) -> HttpResponse { + let error_reason = match self { + EnqueueRerenderAnimationError::BadInput(reason) => reason.to_string(), + EnqueueRerenderAnimationError::NotAuthorized => "unauthorized".to_string(), + EnqueueRerenderAnimationError::ServerError => "server error".to_string(), + EnqueueRerenderAnimationError::RateLimited => "rate limited".to_string(), + }; + + to_simple_json_error(&error_reason, self.status_code()) + } +} + +// NB: Not using derive_more::Display since Clion doesn't understand it. +impl std::fmt::Display for EnqueueRerenderAnimationError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + +pub async fn enqueue_rerender_animation_handler( + http_request: HttpRequest, + request: web::Json, + server_state: web::Data>) -> Result +{ + let mut maybe_user_token : Option = None; + + let mut mysql_connection = server_state.mysql_pool + .acquire() + .await + .map_err(|err| { + warn!("MySql pool error: {:?}", err); + EnqueueRerenderAnimationError::ServerError + })?; + + let maybe_avt_token = server_state.avt_cookie_manager.get_avt_token_from_request(&http_request); + + // ==================== USER SESSION ==================== // + + let maybe_user_session = server_state + .session_checker + .maybe_get_user_session_extended_from_connection(&http_request, &mut mysql_connection) + .await + .map_err(|e| { + warn!("Session checker error: {:?}", e); + EnqueueRerenderAnimationError::ServerError + })?; + + if let Some(user_session) = maybe_user_session.as_ref() { + maybe_user_token = Some(UserToken::new_from_str(&user_session.user_token)); + } + + // TODO: Plan should handle "first anonymous use" and "investor" cases. + let plan = get_correct_plan_for_session( + server_state.server_environment, + maybe_user_session.as_ref()); + + // TODO: Separate priority for animation. + let priority_level = plan.web_vc_base_priority_level(); + + // ==================== DEBUG MODE + ROUTING TAG ==================== // + + let is_debug_request = + get_request_header_optional(&http_request, DEBUG_HEADER_NAME) + .is_some(); + + let maybe_routing_tag= + get_request_header_optional(&http_request, ROUTING_TAG_HEADER_NAME) + .map(|routing_tag| routing_tag.trim().to_string()); + + // ==================== RATE LIMIT ==================== // + + let rate_limiter = match maybe_user_session { + None => &server_state.redis_rate_limiters.logged_out, + Some(ref user) => { + if user.role.is_banned { + return Err(EnqueueRerenderAnimationError::NotAuthorized); + } + &server_state.redis_rate_limiters.logged_in + }, + }; + + if let Err(_err) = rate_limiter.rate_limit_request(&http_request) { + return Err(EnqueueRerenderAnimationError::RateLimited); + } + + // ==================== LOOK UP MODEL INFO ==================== // + + // TODO(bt): CHECK DATABASE FOR TOKENS! + + let video_source: VideofilterVideoSource = { + if let Some(ref token) = request.video_source.maybe_media_file_token { + VideofilterVideoSource::media_file_token(token.as_str()) + } else if let Some(ref token) = request.video_source.maybe_media_upload_token { + VideofilterVideoSource::media_upload_token(token.as_str()) + } else { + return Err(EnqueueRerenderAnimationError::BadInput("video source not fully specified".to_string())); + } + }; + + let ip_address = get_request_ip(&http_request); + + let maybe_user_preferred_visibility : Option = maybe_user_session + .as_ref() + .map(|user_session: &users_component::utils::user_session_extended::UserSessionExtended| user_session.preferences.preferred_tts_result_visibility); // TODO: New setting for web-vc + + let set_visibility = request.creator_set_visibility + .or(maybe_user_preferred_visibility) + .unwrap_or(Visibility::Public); + + let inference_args = RerenderArgs { + maybe_video_source: Some(video_source), + maybe_sd_model: Some(request.sd_model.clone()), + }; + + info!("Creating rerender animation job record..."); + + let query_result = insert_generic_inference_job(InsertGenericInferenceArgs { + uuid_idempotency_token: &request.uuid_idempotency_token, + inference_category: InferenceCategory::RerenderAVideo, + maybe_model_type: Some(InferenceModelType::RerenderAVideo), // NB: Model is static during inference + maybe_model_token: None, // NB: Model is static during inference + maybe_input_source_token: None, // TODO: Introduce a second foreign key ? + maybe_input_source_token_type: None, // TODO: Introduce a second foreign key ? + maybe_raw_inference_text: None, // No text + maybe_max_duration_seconds: None, + maybe_inference_args: Some(GenericInferenceArgs { + inference_category: Some(InferenceCategoryAbbreviated::RerenderAVideo), + args: Some(PolymorphicInferenceArgs::Rr(inference_args)), + }), + maybe_creator_user_token: maybe_user_token.as_ref(), + maybe_avt_token: maybe_avt_token.as_ref(), + creator_ip_address: &ip_address, + creator_set_visibility: set_visibility, + priority_level, + requires_keepalive: plan.rerender_requires_frontent_keepalive(), + is_debug_request, + maybe_routing_tag: maybe_routing_tag.as_deref(), + mysql_pool: &server_state.mysql_pool, + }).await; + + let job_token = match query_result { + Ok((job_token, _id)) => job_token, + Err(err) => { + warn!("New generic inference job creation DB error: {:?}", err); + return Err(EnqueueRerenderAnimationError::ServerError); + } + }; + + let response: EnqueueRerenderAnimationSuccessResponse = EnqueueRerenderAnimationSuccessResponse { + success: true, + inference_job_token: job_token, + }; + + let body = serde_json::to_string(&response) + .map_err(|_e| EnqueueRerenderAnimationError::ServerError)?; + + Ok(HttpResponse::Ok() + .content_type("application/json") + .body(body)) +} diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/animation/mod.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/animation/mod.rs index 1102d9357d..5a9c5c080e 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/animation/mod.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/animation/mod.rs @@ -1 +1,2 @@ -pub mod enqueue_lipsync_animation; \ No newline at end of file +pub mod enqueue_lipsync_animation; +pub mod enqueue_rerender_animation; \ No newline at end of file diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/inference_job/get_inference_job_status.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/inference_job/get_inference_job_status.rs index 96be5ed7d7..d227585c20 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/inference_job/get_inference_job_status.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/inference_job/get_inference_job_status.rs @@ -256,6 +256,14 @@ fn record_to_payload( .get_full_object_path_str() .to_string() } + InferenceCategory::RerenderAVideo => { + MediaFileBucketPath::from_object_hash( + &result_details.public_bucket_location_or_hash, + result_details.maybe_media_file_public_bucket_prefix.as_deref(), + result_details.maybe_media_file_public_bucket_extension.as_deref()) + .get_full_object_path_str() + .to_string() + } InferenceCategory::TextToSpeech => { match result_details.entity_type.as_str() { "media_file" => { diff --git a/crates/service/web/storyteller_web/src/routes.rs b/crates/service/web/storyteller_web/src/routes.rs index f612d034f7..96be089846 100644 --- a/crates/service/web/storyteller_web/src/routes.rs +++ b/crates/service/web/storyteller_web/src/routes.rs @@ -12,6 +12,7 @@ use users_component::endpoints::edit_profile_handler::edit_profile_handler; use users_component::endpoints::get_profile_handler::get_profile_handler; use crate::http_server::endpoints::animation::enqueue_lipsync_animation::enqueue_lipsync_animation_handler; +use crate::http_server::endpoints::animation::enqueue_rerender_animation::enqueue_rerender_animation_handler; use crate::http_server::endpoints::api_tokens::create_api_token::create_api_token_handler; use crate::http_server::endpoints::api_tokens::delete_api_token::delete_api_token_handler; use crate::http_server::endpoints::api_tokens::edit_api_token::edit_api_token_handler; From 14432cce83a8dde04613d0a8fc45a8b7bbf0e6fd Mon Sep 17 00:00:00 2001 From: salt Date: Tue, 12 Dec 2023 15:12:34 -0800 Subject: [PATCH 020/124] fix errors --- .../src/job/job_loop/process_single_job.rs | 3 +- .../src/job/job_types/videofilter/mod.rs | 2 +- .../videofilter/process_single_vf_job.rs | 35 ++++++++++--------- .../videofilter/rerender_a_video/mod.rs | 2 +- .../{process_jobs.rs => process_job.rs} | 0 .../rerender_inference_command.rs | 20 +++++++++-- .../traits/internal_session_cache_purge.rs | 4 +-- 7 files changed, 41 insertions(+), 25 deletions(-) rename crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/{process_jobs.rs => process_job.rs} (100%) diff --git a/crates/service/job/inference_job/src/job/job_loop/process_single_job.rs b/crates/service/job/inference_job/src/job/job_loop/process_single_job.rs index 6dc5a4f7d4..c7edcdbb7f 100644 --- a/crates/service/job/inference_job/src/job/job_loop/process_single_job.rs +++ b/crates/service/job/inference_job/src/job/job_loop/process_single_job.rs @@ -16,6 +16,7 @@ use crate::job::job_loop::process_single_job_success_case::ProcessSingleJobSucce use crate::job::job_types::lipsync::process_single_lipsync_job::process_single_lipsync_job; use crate::job::job_types::tts::process_single_tts_job::process_single_tts_job; use crate::job::job_types::vc::process_single_vc_job::process_single_vc_job; +use crate::job::job_types::videofilter::process_single_vf_job::process_single_rr_job; use crate::job_dependencies::JobDependencies; pub async fn process_single_job( @@ -183,7 +184,7 @@ async fn do_process_single_job( process_single_vc_job(job_dependencies, job).await? } InferenceCategory::RerenderAVideo => { - process_single_rerender_job(job_dependencies, job).await? + process_single_rr_job(job_dependencies, job).await? } }; diff --git a/crates/service/job/inference_job/src/job/job_types/videofilter/mod.rs b/crates/service/job/inference_job/src/job/job_types/videofilter/mod.rs index 7f70f41199..305ceb8a28 100644 --- a/crates/service/job/inference_job/src/job/job_types/videofilter/mod.rs +++ b/crates/service/job/inference_job/src/job/job_types/videofilter/mod.rs @@ -1,2 +1,2 @@ pub(crate) mod rerender_a_video; -mod process_single_vf_job; +pub(crate) mod process_single_vf_job; diff --git a/crates/service/job/inference_job/src/job/job_types/videofilter/process_single_vf_job.rs b/crates/service/job/inference_job/src/job/job_types/videofilter/process_single_vf_job.rs index eee4f2cd8d..6a35427d0e 100644 --- a/crates/service/job/inference_job/src/job/job_types/videofilter/process_single_vf_job.rs +++ b/crates/service/job/inference_job/src/job/job_types/videofilter/process_single_vf_job.rs @@ -1,19 +1,13 @@ -use std::time::Duration; - use anyhow::anyhow; use log::{error, info}; -use enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType; use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob; use mysql_queries::queries::media_uploads::get_media_upload_for_inference::get_media_upload_for_inference; -use mysql_queries::queries::voice_conversion::inference::get_voice_conversion_model_for_inference::get_voice_conversion_model_for_inference; use tokens::tokens::media_uploads::MediaUploadToken; use crate::job::job_loop::job_success_result::JobSuccessResult; use crate::job::job_loop::process_single_job_error::ProcessSingleJobError; -use crate::job::job_types::vc::{rvc_v2, so_vits_svc}; -use crate::job::job_types::vc::rvc_v2::process_job::RvcV2ProcessJobArgs; -use crate::job::job_types::vc::so_vits_svc::process_job::SoVitsSvcProcessJobArgs; +use crate::job::job_types::videofilter::rerender_a_video; use crate::job_dependencies::JobDependencies; pub async fn process_single_rr_job(job_dependencies: &JobDependencies, job: &AvailableInferenceJob) -> Result { @@ -47,17 +41,24 @@ pub async fn process_single_rr_job(job_dependencies: &JobDependencies, job: &Ava - let job_success_result = match vc_model.model_type { - VoiceConversionModelType::RvcV2 => { - rvc_v2::process_job::process_job(RvcV2ProcessJobArgs { - job_dependencies, - job, - vc_model: &vc_model, - media_upload_token: &media_upload_token, - media_upload: &media_upload, - }).await? + // let job_success_result = match vc_model.model_type { + // VoiceConversionModelType::RvcV2 => { + // rvc_v2::process_job::process_job(RvcV2ProcessJobArgs { + // job_dependencies, + // job, + // vc_model: &vc_model, + // media_upload_token: &media_upload_token, + // media_upload: &media_upload, + // }).await? + // } + // }; + + let job_success_result = rerender_a_video::process_job::process_job( + rerender_a_video::process_job::RerenderProcessJobArgs { + job_dependencies, + job } - }; + ).await?; Ok(job_success_result) } diff --git a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/mod.rs b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/mod.rs index 711397cfb1..28c9dea48a 100644 --- a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/mod.rs +++ b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/mod.rs @@ -1,4 +1,4 @@ -mod process_jobs; +pub(crate) mod process_job; mod validate_job; mod download_video_file; mod rerender_inference_command; diff --git a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/process_jobs.rs b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/process_job.rs similarity index 100% rename from crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/process_jobs.rs rename to crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/process_job.rs diff --git a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/rerender_inference_command.rs b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/rerender_inference_command.rs index 2c221e2b28..8b0b011893 100644 --- a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/rerender_inference_command.rs +++ b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/rerender_inference_command.rs @@ -77,9 +77,9 @@ impl RerenderInferenceCommand { maybe_execution_timeout: Option, ) -> Self { Self { - rerender_root_code_directory: rerender_root_code_directory.as_ref().to_path_buf(), + rerender_root_code_directory: rerender_root_code_directory.clone(), executable_or_command, - config_path: config_path.as_ref().to_path_buf(), + config_path: config_path.clone(), maybe_virtual_env_activation_command: maybe_virtual_env_activation_command.map(|s| s.to_string()), maybe_docker_options, maybe_execution_timeout, @@ -93,6 +93,20 @@ impl RerenderInferenceCommand { let config_path = easyenv::get_env_pathbuf_required( "RERENDER_INFERENCE_CONFIG_PATH")?; + let executable_or_command = match easyenv::get_env_string_optional( + "RERENDER_INFERENCE_EXECUTABLE_OR_COMMAND") { + None => { + return Err(anyhow!("RERENDER_INFERENCE_EXECUTABLE_OR_COMMAND is required")); + } + Some(executable_or_command) => { + if executable_or_command.contains(" ") { + ExecutableOrCommand::Command(executable_or_command) + } else { + ExecutableOrCommand::Executable(PathBuf::from(executable_or_command)) + } + } + }; + let maybe_virtual_env_activation_command = easyenv::get_env_string_optional( "RERENDER_INFERENCE_MAYBE_VENV_COMMAND"); @@ -192,7 +206,7 @@ impl RerenderInferenceCommand { let mut config = PopenConfig::default(); - info!("stderr will be written to file: {:?}", args.stderr_output_file.as_ref()); + info!("stderr will be written to file: {:?}", args.stderr_output_file.as_os_str()); let stderr_file = File::create(&args.stderr_output_file)?; config.stderr = Redirection::File(stderr_file); diff --git a/crates/service/plugins/billing/src/stripe/traits/internal_session_cache_purge.rs b/crates/service/plugins/billing/src/stripe/traits/internal_session_cache_purge.rs index 69abd86b95..cc4df2852d 100644 --- a/crates/service/plugins/billing/src/stripe/traits/internal_session_cache_purge.rs +++ b/crates/service/plugins/billing/src/stripe/traits/internal_session_cache_purge.rs @@ -1,8 +1,8 @@ use actix_web::HttpRequest; -use mockall::automock; +// use mockall::automock; /// Allows us to purge session caches that might keep stale premium plan/billing data around -#[cfg_attr(test, automock)] +// #[cfg_attr(test, automock)] pub trait InternalSessionCachePurge { /// Best effort attempt to delete /// Fails silently. From e5a85c752821c75f610f0dc2bd794dbc4974edfd Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Tue, 12 Dec 2023 18:56:02 -0500 Subject: [PATCH 021/124] fix failing doctest --- crates/vendor/limitation/src/lib.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/crates/vendor/limitation/src/lib.rs b/crates/vendor/limitation/src/lib.rs index 649b30eb46..b40cf6b1fe 100644 --- a/crates/vendor/limitation/src/lib.rs +++ b/crates/vendor/limitation/src/lib.rs @@ -42,9 +42,12 @@ //! // The key to count and track //! let key = "10.0.0.5"; //! +//! // TODO(bt,2023-12-12): This doctest is so far behind in `futures` versions and needs to be updated. +//! // Tokio should be executing the future and evaluating the result. //! // Start and run a Tokio runtime to drive the Future to completion -//! tokio::run( -//! limiter +//! //let mut rt = tokio::runtime::Runtime::new().unwrap(); +//! //rt.block_on(...)//! +//! let _r = limiter //! // Count returns a Status if the key is under the limit and an `Error::LimitExceeded` //! // containing a Status if the limit has been exceeded //! .count(key) @@ -57,8 +60,9 @@ //! .and_then(|status| { //! println!("ok: {:?}", status); //! Ok(()) -//! }), -//! ); +//! }) +//! .wait(); +//! //); //! # Ok::<(), limitation::Error>(()) //! ``` //! From e375c8090c658bd52ee6d8cd73b0078bdf457343 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Tue, 12 Dec 2023 19:21:42 -0500 Subject: [PATCH 022/124] fix IDE handling (code compiled and tested, but IDE unhappy) --- .../billing/src/stripe/traits/internal_session_cache_purge.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/service/plugins/billing/src/stripe/traits/internal_session_cache_purge.rs b/crates/service/plugins/billing/src/stripe/traits/internal_session_cache_purge.rs index d125c53d7f..df5bae0773 100644 --- a/crates/service/plugins/billing/src/stripe/traits/internal_session_cache_purge.rs +++ b/crates/service/plugins/billing/src/stripe/traits/internal_session_cache_purge.rs @@ -1,7 +1,7 @@ use actix_web::HttpRequest; /// Allows us to purge session caches that might keep stale premium plan/billing data around -#[cfg_attr(test, automock)] +#[cfg_attr(test, mockall::automock)] pub trait InternalSessionCachePurge { /// Best effort attempt to delete /// Fails silently. From d51ee67d4c066b111da06352dde0835777d85c0d Mon Sep 17 00:00:00 2001 From: salt Date: Tue, 12 Dec 2023 17:35:36 -0800 Subject: [PATCH 023/124] complete failure --- .../inference_category.rs | 8 ++++++- .../inference_model_type.rs | 6 +++-- .../config/inference-job.development.env | 9 +++++++ .../rerender_inference_command.rs | 24 +++---------------- .../animation/enqueue_rerender_animation.rs | 12 ++-------- 5 files changed, 25 insertions(+), 34 deletions(-) diff --git a/crates/_types/enums/src/by_table/generic_inference_jobs/inference_category.rs b/crates/_types/enums/src/by_table/generic_inference_jobs/inference_category.rs index b96b6fb261..d1a420544b 100644 --- a/crates/_types/enums/src/by_table/generic_inference_jobs/inference_category.rs +++ b/crates/_types/enums/src/by_table/generic_inference_jobs/inference_category.rs @@ -50,6 +50,7 @@ impl InferenceCategory { "lipsync_animation" => Ok(Self::LipsyncAnimation), "text_to_speech" => Ok(Self::TextToSpeech), "voice_conversion" => Ok(Self::VoiceConversion), + "rerender_a_video" => Ok(Self::RerenderAVideo), _ => Err(format!("invalid value: {:?}", value)), } } @@ -61,6 +62,7 @@ impl InferenceCategory { Self::LipsyncAnimation, Self::TextToSpeech, Self::VoiceConversion, + Self::RerenderAVideo, ]) } } @@ -75,6 +77,7 @@ mod tests { assert_serialization(InferenceCategory::LipsyncAnimation, "lipsync_animation"); assert_serialization(InferenceCategory::TextToSpeech, "text_to_speech"); assert_serialization(InferenceCategory::VoiceConversion, "voice_conversion"); + assert_serialization(InferenceCategory::RerenderAVideo, "rerender_a_video"); } #[test] @@ -82,6 +85,7 @@ mod tests { assert_eq!(InferenceCategory::LipsyncAnimation.to_str(), "lipsync_animation"); assert_eq!(InferenceCategory::TextToSpeech.to_str(), "text_to_speech"); assert_eq!(InferenceCategory::VoiceConversion.to_str(), "voice_conversion"); + assert_eq!(InferenceCategory::RerenderAVideo.to_str(), "rerender_a_video"); } #[test] @@ -89,16 +93,18 @@ mod tests { assert_eq!(InferenceCategory::from_str("lipsync_animation").unwrap(), InferenceCategory::LipsyncAnimation); assert_eq!(InferenceCategory::from_str("text_to_speech").unwrap(), InferenceCategory::TextToSpeech); assert_eq!(InferenceCategory::from_str("voice_conversion").unwrap(), InferenceCategory::VoiceConversion); + assert_eq!(InferenceCategory::from_str("rerender_a_video").unwrap(), InferenceCategory::RerenderAVideo); } #[test] fn all_variants() { // Static check let mut variants = InferenceCategory::all_variants(); - assert_eq!(variants.len(), 3); + assert_eq!(variants.len(), 4); assert_eq!(variants.pop_first(), Some(InferenceCategory::LipsyncAnimation)); assert_eq!(variants.pop_first(), Some(InferenceCategory::TextToSpeech)); assert_eq!(variants.pop_first(), Some(InferenceCategory::VoiceConversion)); + assert_eq!(variants.pop_first(), Some(InferenceCategory::RerenderAVideo)); assert_eq!(variants.pop_first(), None); // Generated check diff --git a/crates/_types/enums/src/by_table/generic_inference_jobs/inference_model_type.rs b/crates/_types/enums/src/by_table/generic_inference_jobs/inference_model_type.rs index 0a30156539..c5c312b300 100644 --- a/crates/_types/enums/src/by_table/generic_inference_jobs/inference_model_type.rs +++ b/crates/_types/enums/src/by_table/generic_inference_jobs/inference_model_type.rs @@ -49,7 +49,7 @@ impl InferenceModelType { Self::Tacotron2 => "tacotron2", Self::Vits => "vits", Self::VallEX => "vall_e_x", - Self::RerenderAVideo => "rerender_a_video", + Self::RerenderAVideo => "rerender_a_video", } } @@ -61,6 +61,7 @@ impl InferenceModelType { "tacotron2" => Ok(Self::Tacotron2), "vits" => Ok(Self::Vits), "vall_e_x" => Ok(Self::VallEX), + "rerender_a_video" => Ok(Self::RerenderAVideo), _ => Err(format!("invalid value: {:?}", value)), } } @@ -74,7 +75,8 @@ impl InferenceModelType { InferenceModelType::SoVitsSvc, InferenceModelType::Tacotron2, InferenceModelType::Vits, - InferenceModelType::VallEX + InferenceModelType::VallEX, + InferenceModelType::RerenderAVideo ]) } } diff --git a/crates/service/job/inference_job/config/inference-job.development.env b/crates/service/job/inference_job/config/inference-job.development.env index 0df22ea669..359c8edf3e 100644 --- a/crates/service/job/inference_job/config/inference-job.development.env +++ b/crates/service/job/inference_job/config/inference-job.development.env @@ -94,6 +94,15 @@ VITS_INFERENCE_SCRIPT="infer_ts_job.py" VITS_INFERENCE_MAYBE_PYTHON_INTERPRETER="python3" VITS_INFERENCE_MAYBE_DOCKER_IMAGE_SHA="03017896367b" + +# ================================= # +# # +# Rerender # +# # +# ================================= # +RERENDER_INFERENCE_ROOT_DIRECTORY="/home/salt/clone/storyteller-ml/animation/rerender-lora/" +RERENDER_INFERENCE_EXECUTABLE_OR_COMMAND="conda activate rerender && python rerender.py" + # ================================= # # # # CACHE SETTINGS # diff --git a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/rerender_inference_command.rs b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/rerender_inference_command.rs index 8b0b011893..a3ba8953ae 100644 --- a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/rerender_inference_command.rs +++ b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/rerender_inference_command.rs @@ -40,7 +40,7 @@ pub struct RerenderInferenceCommand { executable_or_command: ExecutableOrCommand, /// Config file to use - config_path: PathBuf, + config_path: Option, /// eg. `source python/bin/activate` maybe_virtual_env_activation_command: Option, @@ -68,30 +68,12 @@ pub struct InferenceArgs<'s, P: AsRef> { } impl RerenderInferenceCommand { - pub fn new>( - rerender_root_code_directory: PathBuf, - executable_or_command: ExecutableOrCommand, - config_path: PathBuf, - maybe_virtual_env_activation_command: Option, - maybe_docker_options: Option, - maybe_execution_timeout: Option, - ) -> Self { - Self { - rerender_root_code_directory: rerender_root_code_directory.clone(), - executable_or_command, - config_path: config_path.clone(), - maybe_virtual_env_activation_command: maybe_virtual_env_activation_command.map(|s| s.to_string()), - maybe_docker_options, - maybe_execution_timeout, - } - } - pub fn from_env() -> AnyhowResult { let rerender_root_code_directory = easyenv::get_env_pathbuf_required( "RERENDER_INFERENCE_ROOT_DIRECTORY")?; - let config_path = easyenv::get_env_pathbuf_required( - "RERENDER_INFERENCE_CONFIG_PATH")?; + let config_path = easyenv::get_env_pathbuf_optional( + "RERENDER_INFERENCE_CONFIG_PATH"); let executable_or_command = match easyenv::get_env_string_optional( "RERENDER_INFERENCE_EXECUTABLE_OR_COMMAND") { diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/animation/enqueue_rerender_animation.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/animation/enqueue_rerender_animation.rs index 1519e5332b..d90caa3b8b 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/animation/enqueue_rerender_animation.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/animation/enqueue_rerender_animation.rs @@ -20,7 +20,6 @@ use mysql_queries::payloads::generic_inference_args::videofilter_payload::{Reren use mysql_queries::queries::generic_inference::web::insert_generic_inference_job::{insert_generic_inference_job, InsertGenericInferenceArgs}; use tokens::tokens::generic_inference_jobs::InferenceJobToken; use tokens::tokens::media_files::MediaFileToken; -use tokens::tokens::media_uploads::MediaUploadToken; use tokens::tokens::users::UserToken; use crate::configs::plans::get_correct_plan_for_session::get_correct_plan_for_session; @@ -39,17 +38,12 @@ const ROUTING_TAG_HEADER_NAME : &str = "routing-tag"; pub struct EnqueueRerenderAnimationRequest { uuid_idempotency_token: String, - video_source: VideoSource, + video_source: Option, sd_model: String, creator_set_visibility: Option, } /// Treated as an enum. Only one of these may be set. -#[derive(Deserialize)] -pub struct VideoSource { - maybe_media_file_token: Option, - maybe_media_upload_token: Option, -} #[derive(Serialize)] pub struct EnqueueRerenderAnimationSuccessResponse { @@ -165,10 +159,8 @@ pub async fn enqueue_rerender_animation_handler( // TODO(bt): CHECK DATABASE FOR TOKENS! let video_source: VideofilterVideoSource = { - if let Some(ref token) = request.video_source.maybe_media_file_token { + if let Some(ref token) = request.video_source { VideofilterVideoSource::media_file_token(token.as_str()) - } else if let Some(ref token) = request.video_source.maybe_media_upload_token { - VideofilterVideoSource::media_upload_token(token.as_str()) } else { return Err(EnqueueRerenderAnimationError::BadInput("video source not fully specified".to_string())); } From 292b831d1697d4912632a02cba080620fba55854 Mon Sep 17 00:00:00 2001 From: salt Date: Tue, 12 Dec 2023 17:36:53 -0800 Subject: [PATCH 024/124] update tests --- .../by_table/generic_inference_jobs/inference_model_type.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/_types/enums/src/by_table/generic_inference_jobs/inference_model_type.rs b/crates/_types/enums/src/by_table/generic_inference_jobs/inference_model_type.rs index c5c312b300..a3ea0bcd29 100644 --- a/crates/_types/enums/src/by_table/generic_inference_jobs/inference_model_type.rs +++ b/crates/_types/enums/src/by_table/generic_inference_jobs/inference_model_type.rs @@ -94,6 +94,7 @@ mod tests { assert_serialization(InferenceModelType::Tacotron2, "tacotron2"); assert_serialization(InferenceModelType::Vits, "vits"); assert_serialization(InferenceModelType::VallEX, "vall_e_x"); + assert_serialization(InferenceModelType::RerenderAVideo, "rerender_a_video"); } #[test] @@ -104,6 +105,7 @@ mod tests { assert_eq!(InferenceModelType::Tacotron2.to_str(), "tacotron2"); assert_eq!(InferenceModelType::Vits.to_str(), "vits"); assert_eq!(InferenceModelType::VallEX.to_str(), "vall_e_x"); + assert_eq!(InferenceModelType::RerenderAVideo.to_str(), "rerender_a_video"); } #[test] @@ -114,19 +116,21 @@ mod tests { assert_eq!(InferenceModelType::from_str("tacotron2").unwrap(), InferenceModelType::Tacotron2); assert_eq!(InferenceModelType::from_str("vits").unwrap(), InferenceModelType::Vits); assert_eq!(InferenceModelType::from_str("vall_e_x").unwrap(), InferenceModelType::VallEX); + assert_eq!(InferenceModelType::from_str("rerender_a_video").unwrap(), InferenceModelType::RerenderAVideo); } #[test] fn all_variants() { // Static check let mut variants = InferenceModelType::all_variants(); - assert_eq!(variants.len(), 6); + assert_eq!(variants.len(), 7); assert_eq!(variants.pop_first(), Some(InferenceModelType::RvcV2)); assert_eq!(variants.pop_first(), Some(InferenceModelType::SadTalker)); assert_eq!(variants.pop_first(), Some(InferenceModelType::SoVitsSvc)); 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(), None); // Generated check From 57e2f70707a2ace6f5ead0407b0ca3c66bc1fb46 Mon Sep 17 00:00:00 2001 From: salt Date: Tue, 12 Dec 2023 23:07:27 -0800 Subject: [PATCH 025/124] WORKING! --- Cargo.lock | 1 + .../generic_synthetic_ids/id_category.rs | 6 + .../media_file_origin_model_type.rs | 7 +- .../media_file_origin_product_category.rs | 6 + .../insert_media_file_from_rerender.rs | 158 ++++++++++++ .../src/queries/media_files/mod.rs | 1 + crates/service/job/inference_job/Cargo.toml | 1 + .../config/inference-job.development.env | 2 +- .../videofilter/process_single_vf_job.rs | 76 +++--- .../rerender_a_video/download_video_file.rs | 32 ++- .../rerender_a_video/process_job.rs | 229 ++++++++++++------ 11 files changed, 415 insertions(+), 104 deletions(-) create mode 100644 crates/lib/mysql_queries/src/queries/media_files/insert_media_file_from_rerender.rs diff --git a/Cargo.lock b/Cargo.lock index 215225d64d..4193767e2c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3070,6 +3070,7 @@ dependencies = [ "newrelic-telemetry", "once_cell", "r2d2_redis", + "rand 0.8.5", "redis_common", "serde", "serde_derive", diff --git a/crates/_types/enums/src/by_table/generic_synthetic_ids/id_category.rs b/crates/_types/enums/src/by_table/generic_synthetic_ids/id_category.rs index eccff8cf4d..01bddb94dd 100644 --- a/crates/_types/enums/src/by_table/generic_synthetic_ids/id_category.rs +++ b/crates/_types/enums/src/by_table/generic_synthetic_ids/id_category.rs @@ -21,6 +21,10 @@ pub enum IdCategory { #[serde(rename = "lipsync_animation")] LipsyncAnimationResult, + // Results from rerender a video + #[serde(rename = "rerender")] + RerenderResult, + /// Results from tacotron2 /// Applies for RVC and SVC #[serde(rename = "tts_result")] @@ -62,6 +66,7 @@ impl IdCategory { Self::ZeroShotVoiceDataset => "zs_dataset", Self::ZeroShotVoiceEmbedding => "zs_voice", Self::ZeroShotTtsResult => "zs_tts_result", + Self::RerenderResult => "rerender", Self::ModelWeights => "model_weights", } } @@ -75,6 +80,7 @@ impl IdCategory { "zs_dataset" => Ok(Self::ZeroShotVoiceDataset), "zs_voice" => Ok(Self::ZeroShotVoiceEmbedding), "zs_tts_result" => Ok(Self::ZeroShotTtsResult), + "rerender" => Ok(Self::RerenderResult), "model_weights" => Ok(Self::ModelWeights), _ => Err(format!("invalid value: {:?}", value)), } diff --git a/crates/_types/enums/src/by_table/media_files/media_file_origin_model_type.rs b/crates/_types/enums/src/by_table/media_files/media_file_origin_model_type.rs index 8cb9685bc7..a79930d8c6 100644 --- a/crates/_types/enums/src/by_table/media_files/media_file_origin_model_type.rs +++ b/crates/_types/enums/src/by_table/media_files/media_file_origin_model_type.rs @@ -30,6 +30,9 @@ pub enum MediaFileOriginModelType { #[serde(rename = "vall_e_x")] VallEX, + + #[serde(rename = "rerender")] + Rerender, } // TODO(bt, 2022-12-21): This desperately needs MySQL integration tests! @@ -45,7 +48,8 @@ impl MediaFileOriginModelType { Self::SadTalker => "sad_talker", Self::SoVitsSvc => "so_vits_svc", Self::Tacotron2 => "tacotron2", - Self::VallEX => "vall_e_x" + Self::VallEX => "vall_e_x", + Self::Rerender => "rerender", } } @@ -56,6 +60,7 @@ impl MediaFileOriginModelType { "so_vits_svc" => Ok(Self::SoVitsSvc), "tacotron2" => Ok(Self::Tacotron2), "vall_e_x" => Ok(Self::VallEX), + "rerender" => Ok(Self::Rerender), _ => Err(format!("invalid value: {:?}", value)), } } diff --git a/crates/_types/enums/src/by_table/media_files/media_file_origin_product_category.rs b/crates/_types/enums/src/by_table/media_files/media_file_origin_product_category.rs index 7b6f2a029a..5965f9b3a9 100644 --- a/crates/_types/enums/src/by_table/media_files/media_file_origin_product_category.rs +++ b/crates/_types/enums/src/by_table/media_files/media_file_origin_product_category.rs @@ -38,6 +38,10 @@ pub enum MediaFileOriginProductCategory { /// Media files created by (or uploaded for) the Zero Shot voice product. #[serde(rename = "zs_voice")] ZeroShotVoice, + + // Media files for Rerender + #[serde(rename = "rerender")] + Rerender, } // TODO(bt, 2022-12-21): This desperately needs MySQL integration tests! @@ -54,6 +58,7 @@ impl MediaFileOriginProductCategory { Self::Unknown => "unknown", Self::VoiceConversion => "voice_conversion", Self::ZeroShotVoice => "zs_voice", + Self::Rerender => "rerender", } } @@ -64,6 +69,7 @@ impl MediaFileOriginProductCategory { "unknown" => Ok(Self::Unknown), "voice_conversion" => Ok(Self::VoiceConversion), "zs_voice" => Ok(Self::ZeroShotVoice), + "rerender" => Ok(Self::Rerender), _ => Err(format!("invalid value: {:?}", value)), } } diff --git a/crates/lib/mysql_queries/src/queries/media_files/insert_media_file_from_rerender.rs b/crates/lib/mysql_queries/src/queries/media_files/insert_media_file_from_rerender.rs new file mode 100644 index 0000000000..c599a4fad0 --- /dev/null +++ b/crates/lib/mysql_queries/src/queries/media_files/insert_media_file_from_rerender.rs @@ -0,0 +1,158 @@ +use anyhow::anyhow; +use sqlx; +use sqlx::MySqlPool; + +use enums::by_table::generic_synthetic_ids::id_category::IdCategory; +use enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory; +use enums::by_table::media_files::media_file_origin_model_type::MediaFileOriginModelType; +use enums::by_table::media_files::media_file_origin_product_category::MediaFileOriginProductCategory; +use enums::by_table::media_files::media_file_type::MediaFileType; +use errors::AnyhowResult; +use tokens::tokens::media_files::MediaFileToken; +use tokens::tokens::users::UserToken; + +use crate::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob; +use crate::queries::generic_synthetic_ids::transactional_increment_generic_synthetic_id::transactional_increment_generic_synthetic_id; + +pub struct InsertArgs<'a> { + pub pool: &'a MySqlPool, + pub job: &'a AvailableInferenceJob, + + pub maybe_mime_type: Option<&'a str>, + pub file_size_bytes: u64, + pub sha256_checksum: &'a str, + // TODO: Media duration. + //pub duration_millis: u64, + + pub public_bucket_directory_hash: &'a str, + pub maybe_public_bucket_prefix: Option<&'a str>, + pub maybe_public_bucket_extension: Option<&'a str>, + + pub is_on_prem: bool, + pub worker_hostname: &'a str, + pub worker_cluster: &'a str, +} + +pub async fn insert_media_file_from_rerender( + args: InsertArgs<'_> +) -> AnyhowResult<(MediaFileToken, u64)> +{ + let result_token = MediaFileToken::generate(); + + let mut maybe_creator_file_synthetic_id : Option = None; + let mut maybe_creator_category_synthetic_id : Option = None; + + let mut transaction = args.pool.begin().await?; + + if let Some(creator_user_token) = args.job.maybe_creator_user_token.as_deref() { + let user_token = UserToken::new_from_str(creator_user_token); + + let next_media_file_id = transactional_increment_generic_synthetic_id( + &user_token, + IdCategory::MediaFile, + &mut transaction + ).await?; + + let next_rerender_id = transactional_increment_generic_synthetic_id( + &user_token, + IdCategory::RerenderResult, + &mut transaction + ).await?; + + maybe_creator_file_synthetic_id = Some(next_media_file_id); + maybe_creator_category_synthetic_id = Some(next_rerender_id); + } + + let creator_ip_address = args.job.creator_ip_address.as_str(); + let creator_set_visibility = args.job.creator_set_visibility.clone(); + + const ORIGIN_CATEGORY : MediaFileOriginCategory = MediaFileOriginCategory::Inference; + const ORIGIN_PRODUCT_CATEGORY : MediaFileOriginProductCategory = MediaFileOriginProductCategory::Rerender; + const ORIGIN_MODEL_TYPE : MediaFileOriginModelType = MediaFileOriginModelType::Rerender; + const MEDIA_TYPE : MediaFileType = MediaFileType::Video; + + let record_id = { + let query_result = sqlx::query!( + r#" +INSERT INTO media_files +SET + token = ?, + + origin_category = ?, + origin_product_category = ?, + maybe_origin_model_type = ?, + + media_type = ?, + maybe_mime_type = ?, + file_size_bytes = ?, + + checksum_sha2 = ?, + + public_bucket_directory_hash = ?, + maybe_public_bucket_prefix = ?, + maybe_public_bucket_extension = ?, + + maybe_creator_user_token = ?, + maybe_creator_anonymous_visitor_token = ?, + creator_ip_address = ?, + + creator_set_visibility = ?, + + maybe_creator_file_synthetic_id = ?, + maybe_creator_category_synthetic_id = ?, + + is_generated_on_prem = ?, + generated_by_worker = ?, + generated_by_cluster = ? + + "#, + result_token.as_str(), + + ORIGIN_CATEGORY.to_str(), + ORIGIN_PRODUCT_CATEGORY.to_str(), + ORIGIN_MODEL_TYPE.to_str(), + + MEDIA_TYPE.to_str(), + args.maybe_mime_type, + args.file_size_bytes, + + args.sha256_checksum, + + args.public_bucket_directory_hash, + args.maybe_public_bucket_prefix, + args.maybe_public_bucket_extension, + + args.job.maybe_creator_user_token, + args.job.maybe_creator_anonymous_visitor_token, + args.job.creator_ip_address, + + args.job.creator_set_visibility.to_str(), + + maybe_creator_file_synthetic_id, + maybe_creator_category_synthetic_id, + + args.is_on_prem, + args.worker_hostname, + args.worker_cluster + ) + .execute(&mut *transaction) + .await; + + let record_id = match query_result { + Ok(res) => { + res.last_insert_id() + }, + Err(err) => { + // TODO: handle better + //transaction.rollback().await?; + return Err(anyhow!("Mysql error: {:?}", err)); + } + }; + + record_id + }; + + transaction.commit().await?; + + Ok((result_token, record_id)) +} diff --git a/crates/lib/mysql_queries/src/queries/media_files/mod.rs b/crates/lib/mysql_queries/src/queries/media_files/mod.rs index 8930a3ae7c..ff431d1cb4 100644 --- a/crates/lib/mysql_queries/src/queries/media_files/mod.rs +++ b/crates/lib/mysql_queries/src/queries/media_files/mod.rs @@ -8,3 +8,4 @@ pub mod insert_media_file_from_zero_shot_tts; pub mod list_media_files; pub mod list_media_files_for_user; pub mod update_media_file; +pub mod insert_media_file_from_rerender; diff --git a/crates/service/job/inference_job/Cargo.toml b/crates/service/job/inference_job/Cargo.toml index 65713e40b0..fb451aa8a1 100644 --- a/crates/service/job/inference_job/Cargo.toml +++ b/crates/service/job/inference_job/Cargo.toml @@ -81,3 +81,4 @@ async-trait = "0.1.58" my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" } time = "0.3.30" mime = "0.3.17" +rand = { version = "0.8.5", features = [] } diff --git a/crates/service/job/inference_job/config/inference-job.development.env b/crates/service/job/inference_job/config/inference-job.development.env index 359c8edf3e..15ab7f6497 100644 --- a/crates/service/job/inference_job/config/inference-job.development.env +++ b/crates/service/job/inference_job/config/inference-job.development.env @@ -101,7 +101,7 @@ VITS_INFERENCE_MAYBE_DOCKER_IMAGE_SHA="03017896367b" # # # ================================= # RERENDER_INFERENCE_ROOT_DIRECTORY="/home/salt/clone/storyteller-ml/animation/rerender-lora/" -RERENDER_INFERENCE_EXECUTABLE_OR_COMMAND="conda activate rerender && python rerender.py" +RERENDER_INFERENCE_EXECUTABLE_OR_COMMAND="venv/bin/python rerender.py" # ================================= # # # diff --git a/crates/service/job/inference_job/src/job/job_types/videofilter/process_single_vf_job.rs b/crates/service/job/inference_job/src/job/job_types/videofilter/process_single_vf_job.rs index 6a35427d0e..9d7cc0163c 100644 --- a/crates/service/job/inference_job/src/job/job_types/videofilter/process_single_vf_job.rs +++ b/crates/service/job/inference_job/src/job/job_types/videofilter/process_single_vf_job.rs @@ -1,43 +1,56 @@ use anyhow::anyhow; -use log::{error, info}; +use log::info; +use mysql_queries::payloads::generic_inference_args::generic_inference_args::PolymorphicInferenceArgs::Rr; +use mysql_queries::payloads::generic_inference_args::videofilter_payload::VideofilterVideoSource; use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob; -use mysql_queries::queries::media_uploads::get_media_upload_for_inference::get_media_upload_for_inference; -use tokens::tokens::media_uploads::MediaUploadToken; +use mysql_queries::queries::media_files::get_media_file::get_media_file; +use tokens::tokens::media_files::MediaFileToken; use crate::job::job_loop::job_success_result::JobSuccessResult; use crate::job::job_loop::process_single_job_error::ProcessSingleJobError; use crate::job::job_types::videofilter::rerender_a_video; +use crate::job::job_types::videofilter::rerender_a_video::process_job::RerenderProcessJobArgs; use crate::job_dependencies::JobDependencies; pub async fn process_single_rr_job(job_dependencies: &JobDependencies, job: &AvailableInferenceJob) -> Result { - let maybe_media_upload_token = job.maybe_input_source_token - .as_deref() - .map(|token| MediaUploadToken::new_from_str(token)); + // let maybe_inference_args = job.maybe_inference_args.as_ref().ok_or(ProcessSingleJobError::Other(anyhow!("Inference args not found")))?; + // + // let maybe_rerender_args = maybe_inference_args.args.as_ref().map(|args| match args { + // Rr(args) => Some(args), + // _ => None, + // }).flatten(); + // + // let rerender_args = match maybe_rerender_args { + // None => return Err(ProcessSingleJobError::Other(anyhow!("Rerender args not found"))), + // Some(args) => args, + // }; + // + // let videofilter_source = rerender_args.maybe_video_source.as_ref().ok_or(ProcessSingleJobError::Other(anyhow!("Video source not found")))?; + // + // let media_file_token = match videofilter_source { + // VideofilterVideoSource::F(token) => token, + // _ => return Err(ProcessSingleJobError::Other(anyhow!("Video source not found"))), + // }; + // + // let media_file_token = MediaFileToken::new_from_str(media_file_token); + // + // info!("media_file_token: {:?}", media_file_token); + // + // + // let media_file = match media_file_result { + // Ok(Some(result)) => result, + // Ok(None) => { + // return Err(ProcessSingleJobError::Other(anyhow!("Media file not found"))); + // } + // Err(e) => { + // return Err(ProcessSingleJobError::Other(anyhow!("Media file not found"))); + // } + // }; - let media_upload_token = match maybe_media_upload_token { - None => return Err(ProcessSingleJobError::Other(anyhow!("no associated media upload for vc job: {:?}", job.inference_job_token))), - Some(token) => token, - }; - - let maybe_media_upload_result = - get_media_upload_for_inference(&media_upload_token, &job_dependencies.db.mysql_pool).await; - - let media_upload = match maybe_media_upload_result { - Ok(Some(media_upload)) => media_upload, - Ok(None) => { - error!("no media upload record found for token: {:?}", media_upload_token); - return Err(ProcessSingleJobError::Other(anyhow!("no media upload record found for token: {:?}", media_upload_token))); - }, - Err(err) => { - error!("error fetching media upload record from db: {:?}", err); - return Err(ProcessSingleJobError::Other(err)); - }, - }; - - info!("Source media upload file size (bytes): {}", &media_upload.original_file_size_bytes); - info!("Source media upload duration (millis): {}", &media_upload.original_duration_millis); - info!("Source media upload duration (seconds): {}", (media_upload.original_duration_millis as f32 / 1000.0)); + // info!("Source media upload file size (bytes): {}", &media_upload.original_file_size_bytes); + // info!("Source media upload duration (millis): {}", &media_upload.original_duration_millis); + // info!("Source media upload duration (seconds): {}", (media_upload.original_duration_millis as f32 / 1000.0)); @@ -54,9 +67,10 @@ pub async fn process_single_rr_job(job_dependencies: &JobDependencies, job: &Ava // }; let job_success_result = rerender_a_video::process_job::process_job( - rerender_a_video::process_job::RerenderProcessJobArgs { + RerenderProcessJobArgs { job_dependencies, - job + job, + // media_file } ).await?; diff --git a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/download_video_file.rs b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/download_video_file.rs index 344592bd08..e05d695841 100644 --- a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/download_video_file.rs +++ b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/download_video_file.rs @@ -4,13 +4,16 @@ use anyhow::anyhow; use log::{error, warn}; use sqlx::MySqlPool; use tempdir::TempDir; +use buckets::public::media_files::original_file::MediaFileBucketPath; use buckets::public::media_uploads::original_file::MediaUploadOriginalFilePath; use cloud_storage::bucket_client::BucketClient; use jobs_common::job_progress_reporter::job_progress_reporter::JobProgressReporter; use mysql_queries::payloads::generic_inference_args::videofilter_payload::VideofilterVideoSource; use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob; +use mysql_queries::queries::media_files::get_media_file::get_media_file; use mysql_queries::queries::media_uploads::get_media_upload_for_inference::get_media_upload_for_inference; +use tokens::tokens::media_files::MediaFileToken; use tokens::tokens::media_uploads::MediaUploadToken; use crate::job::job_loop::process_single_job_error::ProcessSingleJobError; @@ -34,9 +37,32 @@ pub async fn download_video_file( let bucket_object_path; match video_source { - VideofilterVideoSource::F(_media_file_token) => { - // TODO(bt, 2023-09-08): Implement - return Err(ProcessSingleJobError::NotYetImplemented) + VideofilterVideoSource::F(media_file_token) => { + let media_file_token = MediaFileToken::new_from_str(media_file_token); + let media_file_result = get_media_file( + &media_file_token, + false, + mysql_pool + ).await; + match media_file_result { + Ok(Some(result)) => { + let media_file_bucket_path = + MediaFileBucketPath::from_object_hash( + &result.public_bucket_directory_hash, + result.maybe_public_bucket_prefix.as_deref(), + result.maybe_public_bucket_extension.as_deref(), + ); + bucket_object_path = media_file_bucket_path.to_full_object_pathbuf(); + } + Ok(None) => { + return Err(ProcessSingleJobError::from_anyhow_error( + anyhow!("could not find media file: {:?}", media_file_token))) + } + Err(e) => { + error!("could not query media file: {:?}", e); + return Err(ProcessSingleJobError::from_anyhow_error(e)) + } + } } VideofilterVideoSource::U(media_upload_token) => { let media_upload_token = MediaUploadToken::new_from_str(media_upload_token); diff --git a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/process_job.rs b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/process_job.rs index affec1aee3..0df0d80325 100644 --- a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/process_job.rs +++ b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/process_job.rs @@ -1,8 +1,9 @@ use std::fs::read_to_string; use std::time::Instant; -use anyhow::anyhow; +use anyhow::{anyhow, Error}; use log::{error, info, warn}; +use serde::{Deserialize, Serialize}; use buckets::public::media_files::original_file::MediaFileBucketPath; use enums::by_table::generic_inference_jobs::inference_result_type::InferenceResultType; @@ -12,19 +13,16 @@ use filesys::safe_delete_temp_directory::safe_delete_temp_directory; use filesys::safe_delete_temp_file::safe_delete_temp_file; use hashing::sha256::sha256_hash_file::sha256_hash_file; use mimetypes::mimetype_for_file::get_mimetype_for_file; +use mysql_queries::payloads::generic_inference_args::generic_inference_args::PolymorphicInferenceArgs::Rr; use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob; -use mysql_queries::queries::media_files::insert_media_file_from_face_animation::{insert_media_file_from_face_animation, InsertArgs}; -use tokens::tokens::users::UserToken; +use mysql_queries::queries::media_files::insert_media_file_from_rerender::{insert_media_file_from_rerender, InsertArgs}; use crate::job::job_loop::job_success_result::{JobSuccessResult, ResultEntity}; use crate::job::job_loop::process_single_job_error::ProcessSingleJobError; -use crate::job::job_types::lipsync::sad_talker::categorize_error::categorize_error; -// use crate::job::job_types::lipsync::sad_talker::categorize_error::categorize_error; use crate::job::job_types::videofilter::rerender_a_video::download_video_file::download_video_file; use crate::job::job_types::videofilter::rerender_a_video::rerender_inference_command::InferenceArgs; use crate::job::job_types::videofilter::rerender_a_video::validate_job::validate_job; use crate::job_dependencies::JobDependencies; -use crate::util::common_commands::ffmpeg_logo_watermark_command; /// The maximum that either width or height can be const MAX_DIMENSION : u32 = 1500; @@ -35,6 +33,7 @@ const BUCKET_FILE_EXTENSION: &str = ".mp4"; pub struct RerenderProcessJobArgs<'a> { pub job_dependencies: &'a JobDependencies, pub job: &'a AvailableInferenceJob, + // pub media_file: MediaFile, } pub async fn process_job(args: RerenderProcessJobArgs<'_>) -> Result { @@ -88,43 +87,8 @@ pub async fn process_job(args: RerenderProcessJobArgs<'_>) -> Result { - // error!("Image resize failure: {:?}", err); - // safe_delete_temp_file(&audio_path.filesystem_path); - // safe_delete_temp_file(&image_path.filesystem_path); - // safe_delete_temp_directory(&work_temp_dir); - // return Err(ProcessSingleJobError::Other(anyhow!("image resize failure: {:?}", err))); - // } - // Ok(resized_image_path) => { - // usable_image_path = resized_image_path; - // } - // } - // } + + //TODO: re encode with ffmpeg info!("Used video file: {:?}", usable_video_path); @@ -148,15 +112,43 @@ pub async fn process_job(args: RerenderProcessJobArgs<'_>) -> Result return Err(ProcessSingleJobError::Other(anyhow!("Rerender args not found"))), + Some(args) => args, + }; + + let rr_args = match poly_args { + Rr(args) => args, + _ => return Err(ProcessSingleJobError::Other(anyhow!("Rerender args not found"))), + }; + + let sd_model = rr_args.maybe_sd_model.as_ref().ok_or(ProcessSingleJobError::Other(anyhow!("SD model not found")))?; + + // ============== CREATE AND WRITE CONFIG TO DISK ============== // + + // create seed if not exists + // let seed = rr_args.seed.unwrap_or_else(|| rand::random::()); + let seed = rand::random::(); + + let config = RerenderConfig { + input: Some(usable_video_path.to_str().unwrap().to_string()), + output: Some(output_video_fs_path.to_str().unwrap().to_string()), + work_dir: Some(work_temp_dir.path().to_str().unwrap().to_string()), + sd_model: Some(sd_model.to_string()), + prompt: Some("1girl, anime style, red hair".to_string()), + a_prompt: Some("1girl, 3d, realistic, read hair".to_string()), + n_prompt: Some("Bad quality, low quality, photo, artifacts, watermark, signature, faceless".to_string()), + seed: Some(seed as i64), + ..RerenderConfig::new() + }; + + config.validate().map_err(|e| ProcessSingleJobError::Other(anyhow!(e)))?; let config_path = work_temp_dir.path().join("config.json"); - - // TODO + let config_json = serde_json::to_string(&config).unwrap(); + std::fs::write(&config_path, config_json).unwrap(); // ==================== RUN INFERENCE SCRIPT ==================== // - - let workdir = work_temp_dir.path().to_path_buf(); let stderr_output_file = work_temp_dir.path().join("stderr.txt"); let inference_start_time = Instant::now(); @@ -174,7 +166,7 @@ pub async fn process_job(args: RerenderProcessJobArgs<'_>) -> Result) -> Result) -> Result) -> Result) -> Result) -> Result, + + #[serde(rename = "output")] + pub output: Option, + + #[serde(rename = "work_dir")] + pub work_dir: Option, + + #[serde(rename = "key_subdir")] + pub key_subdir: Option, + + #[serde(rename = "sd_model")] + pub sd_model: Option, + + #[serde(rename = "lora_path")] + pub lora_path: Option, + + #[serde(rename = "interval")] + pub interval: Option, + + #[serde(rename = "prompt")] + pub prompt: Option, + + #[serde(rename = "a_prompt")] + pub a_prompt: Option, + + #[serde(rename = "n_prompt")] + pub n_prompt: Option, + + #[serde(rename = "x0_strength")] + pub x0_strength: Option, + + #[serde(rename = "control_type")] + pub control_type: Option, + + #[serde(rename = "canny_low")] + pub canny_low: Option, + + #[serde(rename = "canny_high")] + pub canny_high: Option, + + #[serde(rename = "control_strength")] + pub control_strength: Option, + + #[serde(rename = "seed")] + pub seed: Option, + + #[serde(rename = "warp_period")] + pub warp_period: Option>, + + #[serde(rename = "ada_period")] + pub ada_period: Option>, +} + +impl RerenderConfig { + pub fn new() -> Self { + Self { + input: None, + output: None, + work_dir: None, + key_subdir: Some("keys".to_string()), + sd_model: None, + lora_path: None, + interval: Some(8), + prompt: None, + a_prompt: None, + n_prompt: None, + x0_strength: Some(0.95), + control_type: Some("canny".to_string()), + canny_low: Some(50), + canny_high: Some(100), + control_strength: Some(0.7), + seed: None, + warp_period: Some(vec![0., 0.1]), + ada_period: Some(vec![0.8, 1.]), + } + } + + pub fn validate(&self) -> Result<(), Error> { + let fields = &[ + (self.input.is_some(), "input"), + (self.output.is_some(), "output"), + (self.work_dir.is_some(), "work_dir"), + (self.key_subdir.is_some(), "key_subdir"), + (self.sd_model.is_some(), "sd_model"), + (self.interval.is_some(), "interval"), + (self.prompt.is_some(), "prompt"), + (self.a_prompt.is_some(), "a_prompt"), + (self.n_prompt.is_some(), "n_prompt"), + (self.x0_strength.is_some(), "x0_strength"), + (self.control_type.is_some(), "control_type"), + (self.canny_low.is_some(), "canny_low"), + (self.canny_high.is_some(), "canny_high"), + (self.control_strength.is_some(), "control_strength"), + (self.seed.is_some(), "seed"), + (self.warp_period.is_some(), "warp_period"), + (self.ada_period.is_some(), "ada_period"), + ]; + + let missing_fields: Vec<&str> = fields + .iter() + .filter_map(|(is_some, field_name)| if *is_some { None } else { Some(*field_name) }) + .collect(); + + if missing_fields.is_empty() { + Ok(()) + } else { + Err(anyhow!("Missing fields: {}", missing_fields.join(", "))) + } + } +} From 196be25fb5a8ccbb660b3f11c85d14d724d7cf59 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Wed, 13 Dec 2023 11:04:13 -0500 Subject: [PATCH 026/124] voice takedown requests --- _sql/actions/voice_conversion_models.sql | 30 ++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/_sql/actions/voice_conversion_models.sql b/_sql/actions/voice_conversion_models.sql index 8520aa609e..9fd7b4ee20 100644 --- a/_sql/actions/voice_conversion_models.sql +++ b/_sql/actions/voice_conversion_models.sql @@ -344,6 +344,36 @@ where token IN ( 'vcm_zmxv2k1q9jd8' ); +update voice_conversion_models +set + mod_deleted_at = NOW(), + maybe_mod_comments = 'takedown request' +where token IN ( + 'vcm_3mzcjkf78x7m', + 'vcm_7k2t1wnyqxsc', + 'vcm_w2edpe6q2nya', + 'vcm_vz9cg294xa29', + 'vcm_0z1ys58589k7', + 'vcm_4x8a30h1r26z', + 'vcm_0vf9prxsww60', + 'vcm_yxbadkvqhg16', + 'vcm_p0ezrc6wvzak', + 'vcm_6r5pbtexyvtp', + 'vcm_pb0ewrf7ych5', + 'vcm_7frb2xk0cxk3', + 'vcm_x129c9s2af06', + 'vcm_e0snndfd59b6', + 'vcm_nb8zb0djqwqw', + 'vcm_2erz5hbh8tpf', + 'vcm_e9wn2ccqe3bk', + 'vcm_f8jbxdbjgcjb', + 'vcm_x02h7z3jqxb0', + 'vcm_xy97xcgnk9y6', + 'vcm_a47wtfbsjrfc', + 'vcm_kygenhbg5mgj', + 'vcm_s8gndv19yt7p' +); + From 3766758cfb33ac0cedf93ced058c117130419883 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Wed, 13 Dec 2023 13:33:48 -0500 Subject: [PATCH 027/124] Rate limiter support for AI streamers --- .../config/storyteller-web.development.env | 3 + .../src/configs/app_startup/mod.rs | 2 + .../app_startup/redis_rate_limiters.rs | 102 ++++++++++++++++++ .../src/configs/app_startup/username_set.rs | 102 ++++++++++++++++++ .../web/storyteller_web/src/configs/mod.rs | 1 + .../enqueue_infer_tts_handler.rs | 19 ++++ .../service/web/storyteller_web/src/main.rs | 67 +----------- .../web/storyteller_web/src/server_state.rs | 7 ++ 8 files changed, 238 insertions(+), 65 deletions(-) create mode 100644 crates/service/web/storyteller_web/src/configs/app_startup/mod.rs create mode 100644 crates/service/web/storyteller_web/src/configs/app_startup/redis_rate_limiters.rs create mode 100644 crates/service/web/storyteller_web/src/configs/app_startup/username_set.rs diff --git a/crates/service/web/storyteller_web/config/storyteller-web.development.env b/crates/service/web/storyteller_web/config/storyteller-web.development.env index 01ffcc593e..c890b5ef3d 100644 --- a/crates/service/web/storyteller_web/config/storyteller-web.development.env +++ b/crates/service/web/storyteller_web/config/storyteller-web.development.env @@ -5,6 +5,9 @@ COOKIE_SECURE=false COOKIE_DOMAIN=.jungle.horse WEBSITE_HOMEPAGE_REDIRECT=http://jungle.horse +# Test the rate limiter bypass (obviously these are dummy values) +AI_STREAMER_USERNAMES="PewDiePie,xQc" + # Stripe configs # All secrets are development and okay to check in STRIPE_CHECKOUT_SUCCESS_URL_PATH=/checkout_success diff --git a/crates/service/web/storyteller_web/src/configs/app_startup/mod.rs b/crates/service/web/storyteller_web/src/configs/app_startup/mod.rs new file mode 100644 index 0000000000..824be656d0 --- /dev/null +++ b/crates/service/web/storyteller_web/src/configs/app_startup/mod.rs @@ -0,0 +1,2 @@ +pub mod redis_rate_limiters; +pub mod username_set; \ No newline at end of file diff --git a/crates/service/web/storyteller_web/src/configs/app_startup/redis_rate_limiters.rs b/crates/service/web/storyteller_web/src/configs/app_startup/redis_rate_limiters.rs new file mode 100644 index 0000000000..1dc2b4d5cd --- /dev/null +++ b/crates/service/web/storyteller_web/src/configs/app_startup/redis_rate_limiters.rs @@ -0,0 +1,102 @@ +use std::time::Duration; + +use log::info; + +use config::common_env::CommonEnv; +use errors::AnyhowResult; +use limitation::Limiter; +use crate::configs::app_startup::username_set::UsernameSet; + +use crate::http_server::web_utils::redis_rate_limiter::RedisRateLimiter; +use crate::server_state::RedisRateLimiters; + + +/// Build the various rate limiters +pub fn configure_redis_rate_limiters(common_env: &CommonEnv) -> AnyhowResult { + // TODO(bt,2023-12-13): Kill CommonEnv. + + info!("Setting up Redis rate limiters..."); + + let logged_out_redis_rate_limiter = { + let limiter_enabled = easyenv::get_env_bool_or_default("LIMITER_LOGGED_OUT_ENABLED", true); + let limiter_max_requests = easyenv::get_env_num("LIMITER_LOGGED_OUT_MAX_REQUESTS", 3)?; + let limiter_window_seconds = easyenv::get_env_num("LIMITER_LOGGED_OUT_WINDOW_SECONDS", 10)?; + + let limiter = Limiter::build(&common_env.redis_0_connection_string) + .limit(limiter_max_requests) + .period(Duration::from_secs(limiter_window_seconds)) + .finish()?; + + RedisRateLimiter::new(limiter, "logged_out", limiter_enabled) + }; + + let logged_in_redis_rate_limiter = { + let limiter_enabled = easyenv::get_env_bool_or_default("LIMITER_LOGGED_IN_ENABLED", true); + let limiter_max_requests = easyenv::get_env_num("LIMITER_LOGGED_IN_MAX_REQUESTS", 3)?; + let limiter_window_seconds = easyenv::get_env_num("LIMITER_LOGGED_IN_WINDOW_SECONDS", 10)?; + + let limiter = Limiter::build(&common_env.redis_0_connection_string) + .limit(limiter_max_requests) + .period(Duration::from_secs(limiter_window_seconds)) + .finish()?; + + RedisRateLimiter::new(limiter, "logged_in", limiter_enabled) + }; + + let api_high_priority_redis_rate_limiter = { + let limiter_enabled = easyenv::get_env_bool_or_default("LIMITER_API_HIGH_PRIORITY_ENABLED", true); + let limiter_max_requests = easyenv::get_env_num("LIMITER_API_HIGH_PRIORITY_MAX_REQUESTS", 30)?; + let limiter_window_seconds = easyenv::get_env_num("LIMITER_API_HIGH_PRIORITY_WINDOW_SECONDS", 30)?; + + let limiter = Limiter::build(&common_env.redis_0_connection_string) + .limit(limiter_max_requests) + .period(Duration::from_secs(limiter_window_seconds)) + .finish()?; + + RedisRateLimiter::new(limiter, "api_high_priority", limiter_enabled) + }; + + // This is for the following users: + // https://www.notion.so/storytellerai/dd88609558a24196b4ddeeef6079da98 + let api_ai_streamers_redis_rate_limiter = { + let limiter_enabled = easyenv::get_env_bool_or_default("LIMITER_API_AI_STREAMERS_ENABLED", true); + let limiter_max_requests = easyenv::get_env_num("LIMITER_API_AI_STREAMERS_MAX_REQUESTS", 30)?; + let limiter_window_seconds = easyenv::get_env_num("LIMITER_API_AI_STREAMERS_WINDOW_SECONDS", 30)?; + + let limiter = Limiter::build(&common_env.redis_0_connection_string) + .limit(limiter_max_requests) + .period(Duration::from_secs(limiter_window_seconds)) + .finish()?; + + RedisRateLimiter::new(limiter, "api_ai_streamers", limiter_enabled) + }; + + let ai_streamer_usernames = + UsernameSet::from_comma_separated(&easyenv::get_env_string_or_default("AI_STREAMER_USERNAMES", "")); + + info!("AI Streamers that can bypass the normal rate limiter ({}): {:?}", + ai_streamer_usernames.len(), + ai_streamer_usernames.list_names()); + + let model_upload_rate_limiter = { + let limiter_enabled = easyenv::get_env_bool_or_default("LIMITER_MODEL_UPLOAD_ENABLED", true); + let limiter_max_requests = easyenv::get_env_num("LIMITER_MODEL_UPLOAD_MAX_REQUESTS", 3)?; + let limiter_window_seconds = easyenv::get_env_num("LIMITER_MODEL_UPLOAD_WINDOW_SECONDS", 10)?; + + let limiter = Limiter::build(&common_env.redis_0_connection_string) + .limit(limiter_max_requests) + .period(Duration::from_secs(limiter_window_seconds)) + .finish()?; + + RedisRateLimiter::new(limiter, "model_upload", limiter_enabled) + }; + + Ok(RedisRateLimiters { + logged_out: logged_out_redis_rate_limiter, + logged_in: logged_in_redis_rate_limiter, + api_high_priority: api_high_priority_redis_rate_limiter, + api_ai_streamers: api_ai_streamers_redis_rate_limiter, + api_ai_streamer_username_set: ai_streamer_usernames, + model_upload: model_upload_rate_limiter, + }) +} diff --git a/crates/service/web/storyteller_web/src/configs/app_startup/username_set.rs b/crates/service/web/storyteller_web/src/configs/app_startup/username_set.rs new file mode 100644 index 0000000000..f9858a201b --- /dev/null +++ b/crates/service/web/storyteller_web/src/configs/app_startup/username_set.rs @@ -0,0 +1,102 @@ +use std::collections::{BTreeSet, HashSet}; + +#[derive(Clone)] +pub struct UsernameSet { + /// "usernames" in our service are always lowercase. + /// "display names" are case sensitive. + usernames: HashSet, +} + +impl UsernameSet { + pub fn from_comma_separated(comma_separated_list: &str) -> Self { + let usernames = comma_separated_list.split(",") + .into_iter() + .map(|item| item.trim()) + .map(|item| item.to_lowercase()) + .filter(|item| !item.is_empty()) + .collect::>(); + Self { + usernames + } + } + + pub fn len(&self) -> usize { + self.usernames.len() + } + + pub fn list_names(&self) -> BTreeSet<&str> { + // NB: BTreeSet for sorting, which is good for logging at app startup + self.usernames.iter().map(|item| item.as_str()).collect::<_>() + } + + pub fn username_is_in_set(&self, username: &str) -> bool { + // We lowercase the input username just in case a display name is passed + let username = username.to_lowercase(); + self.usernames.contains(&username) + } +} + +#[cfg(test)] +mod tests { + use crate::configs::app_startup::username_set::UsernameSet; + fn build_set() -> UsernameSet { + UsernameSet::from_comma_separated("bob,john,ALICE, BoB,jOhn, ,,, , aLiCe, joHn, bob,Alice") + } + #[test] + fn test_deduplication() { + let set = build_set(); + assert_eq!(set.len(), 3); + } + + #[test] + fn test_in_set() { + let set = build_set(); + assert!(set.username_is_in_set("bob")); + assert!(set.username_is_in_set("alice")); + assert!(set.username_is_in_set("john")); + } + + #[test] + fn test_in_set_case_insensitive() { + let set = build_set(); + + assert!(set.username_is_in_set("Bob")); + assert!(set.username_is_in_set("BOB")); + + assert!(set.username_is_in_set("AlIcE")); + assert!(set.username_is_in_set("ALICE")); + + assert!(set.username_is_in_set("jOHN")); + assert!(set.username_is_in_set("JOHN")); + } + + #[test] + fn test_not_in_set() { + let set = build_set(); + + // NB: The build_set() function might have attempted to introduce these, + // but the struct constructor should filter blank spaces out + assert!(!set.username_is_in_set("")); + assert!(!set.username_is_in_set(" ")); + + // Obviously not in set + assert!(!set.username_is_in_set("mary")); + assert!(!set.username_is_in_set("bill")); + + // These usernames are in the set, but not with padding + assert!(!set.username_is_in_set(" alice ")); + assert!(!set.username_is_in_set("bob ")); + assert!(!set.username_is_in_set(" john")); + } + + #[test] + fn test_username_return() { + let set = build_set(); + let usernames = set.list_names(); + assert_eq!(usernames.len(), 3); + assert!(usernames.contains(&"alice")); + assert!(usernames.contains(&"bob")); + assert!(usernames.contains(&"john")); + assert!(!usernames.contains(&"mary")); + } +} diff --git a/crates/service/web/storyteller_web/src/configs/mod.rs b/crates/service/web/storyteller_web/src/configs/mod.rs index 0a735a5b5c..806e1e3209 100644 --- a/crates/service/web/storyteller_web/src/configs/mod.rs +++ b/crates/service/web/storyteller_web/src/configs/mod.rs @@ -1,2 +1,3 @@ +pub mod app_startup; pub mod plans; pub mod static_api_tokens; \ No newline at end of file diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/tts/enqueue_infer_tts_handler/enqueue_infer_tts_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/tts/enqueue_infer_tts_handler/enqueue_infer_tts_handler.rs index b01dd37a5d..cb417f5906 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/tts/enqueue_infer_tts_handler/enqueue_infer_tts_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/tts/enqueue_infer_tts_handler/enqueue_infer_tts_handler.rs @@ -242,7 +242,12 @@ pub async fn enqueue_infer_tts_handler( // ==================== RATE LIMIT ==================== // + // TODO(bt,2023-12-13): Unit test this! if !disable_rate_limiter { + // For AI live streamers + // https://www.notion.so/storytellerai/dd88609558a24196b4ddeeef6079da98 + let mut is_ai_streamer = false; + let mut rate_limiter = match maybe_user_session { None => &server_state.redis_rate_limiters.logged_out, Some(ref user) => { @@ -250,6 +255,15 @@ pub async fn enqueue_infer_tts_handler( warn!("User is not authorized to use TTS model because they are banned."); return Err(InferTtsError::NotAuthorized); } + + if server_state + .redis_rate_limiters + .api_ai_streamer_username_set + .username_is_in_set(&user.user.username) + { + is_ai_streamer = true; + } + &server_state.redis_rate_limiters.logged_in }, }; @@ -264,6 +278,11 @@ pub async fn enqueue_infer_tts_handler( rate_limiter = &server_state.redis_rate_limiters.api_high_priority; } + if is_ai_streamer { + info!("Using AI streamer rate limiter"); + rate_limiter = &server_state.redis_rate_limiters.api_ai_streamers; + } + if let Err(_err) = rate_limiter.rate_limit_request(&http_request) { return Err(InferTtsError::RateLimited); } diff --git a/crates/service/web/storyteller_web/src/main.rs b/crates/service/web/storyteller_web/src/main.rs index e77ed85093..57f09a82c8 100644 --- a/crates/service/web/storyteller_web/src/main.rs +++ b/crates/service/web/storyteller_web/src/main.rs @@ -75,6 +75,7 @@ use crate::billing::internal_product_to_stripe_lookup_impl::InternalProductToStr use crate::billing::internal_session_cache_purge_impl::InternalSessionCachePurgeImpl; use crate::billing::stripe_internal_subscription_product_lookup_impl::StripeInternalSubscriptionProductLookupImpl; use crate::billing::stripe_internal_user_lookup_impl::StripeInternalUserLookupImpl; +use crate::configs::app_startup::redis_rate_limiters::configure_redis_rate_limiters; use crate::configs::static_api_tokens::{StaticApiTokenConfig, StaticApiTokens, StaticApiTokenSet}; use crate::http_server::middleware::pushback_filter_middleware::PushbackFilter; use crate::http_server::web_utils::redis_rate_limiter::RedisRateLimiter; @@ -173,65 +174,6 @@ async fn main() -> AnyhowResult<()> { easyenv::get_env_num("REDIS_CACHE_TTL_SECONDS", 60)?, ); - info!("Setting up Redis rate limiters..."); - - // Old env vars: - // - // "LIMITER_ENABLED" - // "LIMITER_MAX_REQUESTS" - // "LIMITER_WINDOW_SECONDS" - // - let logged_out_redis_rate_limiter = { - let limiter_enabled = easyenv::get_env_bool_or_default("LIMITER_LOGGED_OUT_ENABLED", true); - let limiter_max_requests = easyenv::get_env_num("LIMITER_LOGGED_OUT_MAX_REQUESTS", 3)?; - let limiter_window_seconds = easyenv::get_env_num("LIMITER_LOGGED_OUT_WINDOW_SECONDS", 10)?; - - let limiter = Limiter::build(&common_env.redis_0_connection_string) - .limit(limiter_max_requests) - .period(Duration::from_secs(limiter_window_seconds)) - .finish()?; - - RedisRateLimiter::new(limiter, "logged_out", limiter_enabled) - }; - - let logged_in_redis_rate_limiter = { - let limiter_enabled = easyenv::get_env_bool_or_default("LIMITER_LOGGED_IN_ENABLED", true); - let limiter_max_requests = easyenv::get_env_num("LIMITER_LOGGED_IN_MAX_REQUESTS", 3)?; - let limiter_window_seconds = easyenv::get_env_num("LIMITER_LOGGED_IN_WINDOW_SECONDS", 10)?; - - let limiter = Limiter::build(&common_env.redis_0_connection_string) - .limit(limiter_max_requests) - .period(Duration::from_secs(limiter_window_seconds)) - .finish()?; - - RedisRateLimiter::new(limiter, "logged_in", limiter_enabled) - }; - - let api_high_priority_redis_rate_limiter = { - let limiter_enabled = easyenv::get_env_bool_or_default("LIMITER_API_HIGH_PRIORITY_ENABLED", true); - let limiter_max_requests = easyenv::get_env_num("LIMITER_API_HIGH_PRIORITY_MAX_REQUESTS", 30)?; - let limiter_window_seconds = easyenv::get_env_num("LIMITER_API_HIGH_PRIORITY_WINDOW_SECONDS", 30)?; - - let limiter = Limiter::build(&common_env.redis_0_connection_string) - .limit(limiter_max_requests) - .period(Duration::from_secs(limiter_window_seconds)) - .finish()?; - - RedisRateLimiter::new(limiter, "api_high_priority", limiter_enabled) - }; - - let model_upload_rate_limiter = { - let limiter_enabled = easyenv::get_env_bool_or_default("LIMITER_MODEL_UPLOAD_ENABLED", true); - let limiter_max_requests = easyenv::get_env_num("LIMITER_MODEL_UPLOAD_MAX_REQUESTS", 3)?; - let limiter_window_seconds = easyenv::get_env_num("LIMITER_MODEL_UPLOAD_WINDOW_SECONDS", 10)?; - - let limiter = Limiter::build(&common_env.redis_0_connection_string) - .limit(limiter_max_requests) - .period(Duration::from_secs(limiter_window_seconds)) - .finish()?; - - RedisRateLimiter::new(limiter, "model_upload", limiter_enabled) - }; info!("Connecting to elasticsearch..."); @@ -466,12 +408,7 @@ async fn main() -> AnyhowResult<()> { elasticsearch, redis_pool, redis_ttl_cache, - redis_rate_limiters: RedisRateLimiters { - logged_out: logged_out_redis_rate_limiter, - logged_in: logged_in_redis_rate_limiter, - api_high_priority: api_high_priority_redis_rate_limiter, - model_upload: model_upload_rate_limiter, - }, + redis_rate_limiters: configure_redis_rate_limiters(&common_env)?, firehose_publisher, badge_granter, avt_cookie_manager, diff --git a/crates/service/web/storyteller_web/src/server_state.rs b/crates/service/web/storyteller_web/src/server_state.rs index 41ddadf1d3..a8f86133e2 100644 --- a/crates/service/web/storyteller_web/src/server_state.rs +++ b/crates/service/web/storyteller_web/src/server_state.rs @@ -20,6 +20,7 @@ use url_config::third_party_url_redirector::ThirdPartyUrlRedirector; use users_component::cookies::anonymous_visitor_tracking::avt_cookie_manager::AvtCookieManager; use users_component::cookies::session::session_cookie_manager::SessionCookieManager; use users_component::utils::session_checker::SessionChecker; +use crate::configs::app_startup::username_set::UsernameSet; use crate::http_server::endpoints::categories::tts::list_fully_computed_assigned_tts_categories::list_fully_computed_assigned_tts_categories::ModelTokensByCategoryToken; use crate::http_server::endpoints::leaderboard::get_leaderboard::LeaderboardInfo; @@ -140,6 +141,12 @@ pub struct RedisRateLimiters { /// constructions) pub api_high_priority: RedisRateLimiter, + /// API rate limit for AI streamers + pub api_ai_streamers: RedisRateLimiter, + + /// Usernames of AI streamers + pub api_ai_streamer_username_set: UsernameSet, + /// A rate limiter for TTS and W2L uploads pub model_upload: RedisRateLimiter, } From 81dd377599b08f62d0f7a6d483ebb1238d6c512c Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Wed, 13 Dec 2023 15:27:34 -0500 Subject: [PATCH 028/124] clean up and test rate limiter choice code --- .../src/configs/app_startup/username_set.rs | 1 + .../enqueue_infer_tts_handler.rs | 148 +++++++++++++----- 2 files changed, 114 insertions(+), 35 deletions(-) diff --git a/crates/service/web/storyteller_web/src/configs/app_startup/username_set.rs b/crates/service/web/storyteller_web/src/configs/app_startup/username_set.rs index f9858a201b..0f48cb5350 100644 --- a/crates/service/web/storyteller_web/src/configs/app_startup/username_set.rs +++ b/crates/service/web/storyteller_web/src/configs/app_startup/username_set.rs @@ -42,6 +42,7 @@ mod tests { fn build_set() -> UsernameSet { UsernameSet::from_comma_separated("bob,john,ALICE, BoB,jOhn, ,,, , aLiCe, joHn, bob,Alice") } + #[test] fn test_deduplication() { let set = build_set(); diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/tts/enqueue_infer_tts_handler/enqueue_infer_tts_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/tts/enqueue_infer_tts_handler/enqueue_infer_tts_handler.rs index cb417f5906..2001562038 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/tts/enqueue_infer_tts_handler/enqueue_infer_tts_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/tts/enqueue_infer_tts_handler/enqueue_infer_tts_handler.rs @@ -32,6 +32,7 @@ use tts_common::priority::{FAKEYOU_DEFAULT_VALID_API_TOKEN_PRIORITY_LEVEL, FAKEY use user_input_common::check_for_slurs::contains_slurs; use users_component::utils::user_session_extended::UserSessionExtended; +use crate::configs::app_startup::username_set::UsernameSet; use crate::configs::plans::get_correct_plan_for_session::get_correct_plan_for_session; use crate::configs::plans::plan::Plan; use crate::http_server::endpoints::investor_demo::demo_cookie::request_has_demo_cookie; @@ -240,49 +241,44 @@ pub async fn enqueue_infer_tts_handler( get_request_header_optional(&http_request, ROUTING_TAG_HEADER_NAME) .map(|routing_tag| routing_tag.trim().to_string()); + // ==================== BANNED USERS ==================== // + + if let Some(ref user) = maybe_user_session { + if user.role.is_banned { + warn!("User is not authorized to use TTS model because they are banned."); + return Err(InferTtsError::NotAuthorized); + } + } + // ==================== RATE LIMIT ==================== // - // TODO(bt,2023-12-13): Unit test this! if !disable_rate_limiter { - // For AI live streamers - // https://www.notion.so/storytellerai/dd88609558a24196b4ddeeef6079da98 - let mut is_ai_streamer = false; + let maybe_username = maybe_user_session + .as_ref() + .map(|session| session.user.username.as_str()); - let mut rate_limiter = match maybe_user_session { - None => &server_state.redis_rate_limiters.logged_out, - Some(ref user) => { - if user.role.is_banned { - warn!("User is not authorized to use TTS model because they are banned."); - return Err(InferTtsError::NotAuthorized); - } + // FIXME(bt,2023-12-13): These boolean flags are a bit dangerous. + let rate_limiter_type = get_rate_limiter_type( + maybe_username, + &server_state.redis_rate_limiters.api_ai_streamer_username_set, + is_investor, + is_from_api, + use_high_priority_rate_limiter + ); - if server_state - .redis_rate_limiters - .api_ai_streamer_username_set - .username_is_in_set(&user.user.username) - { - is_ai_streamer = true; - } - - &server_state.redis_rate_limiters.logged_in + let rate_limiter = match rate_limiter_type { + RateLimiterType::LoggedOut => &server_state.redis_rate_limiters.logged_out, + RateLimiterType::LoggedIn => &server_state.redis_rate_limiters.logged_in, + RateLimiterType::ApiHighPriority => { + info!("Using API high priority rate limiter"); + &server_state.redis_rate_limiters.api_high_priority + }, + RateLimiterType::ApiAiStreamer => { + info!("Using AI streamer rate limiter"); + &server_state.redis_rate_limiters.api_ai_streamers }, }; - // TODO/TEMP - if is_investor || is_from_api { - rate_limiter = &server_state.redis_rate_limiters.logged_in; - } - - // TODO: This is for VidVoice.ai and should be replaced with per-API consumer rate limiters - if use_high_priority_rate_limiter { - rate_limiter = &server_state.redis_rate_limiters.api_high_priority; - } - - if is_ai_streamer { - info!("Using AI streamer rate limiter"); - rate_limiter = &server_state.redis_rate_limiters.api_ai_streamers; - } - if let Err(_err) = rate_limiter.rate_limit_request(&http_request) { return Err(InferTtsError::RateLimited); } @@ -495,6 +491,54 @@ pub async fn enqueue_infer_tts_handler( .body(body)) } +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum RateLimiterType { + LoggedOut, + LoggedIn, + ApiHighPriority, + ApiAiStreamer, +} + +// FIXME(bt,2023-12-13): The boolean flags and disjoint decision making are kind of terrible. +fn get_rate_limiter_type( + maybe_username: Option<&str>, + ai_streamer_username_set: &UsernameSet, + is_investor: bool, + is_from_api: bool, + use_high_priority_rate_limiter: bool, +) -> RateLimiterType { + // For AI live streamers + // https://www.notion.so/storytellerai/dd88609558a24196b4ddeeef6079da98 + let mut is_ai_streamer = false; + + let mut rate_limiter = match maybe_username { + None => RateLimiterType::LoggedOut, + Some(username) => { + if ai_streamer_username_set.username_is_in_set(username) { + is_ai_streamer = true; + } + + RateLimiterType::LoggedIn + }, + }; + + // TODO/TEMP + if is_investor || is_from_api { + rate_limiter = RateLimiterType::LoggedIn; + } + + // TODO: This is for VidVoice.ai and should be replaced with per-API consumer rate limiters + if use_high_priority_rate_limiter { + rate_limiter = RateLimiterType::ApiHighPriority; + } + + if is_ai_streamer { + rate_limiter = RateLimiterType::ApiAiStreamer; + } + + rate_limiter +} + pub fn validate_inference_text(text: &str, plan: &Plan) -> Result<(), String> { if text.len() < 3 { return Err("text is too short".to_string()); @@ -561,3 +605,37 @@ fn random_troll_text() -> &'static str { let random = texts.choose(&mut rand::thread_rng()); random.map(|r| *r).unwrap_or(texts[0]) } + + +#[cfg(test)] +mod tests { + + mod rate_limiter_tests { + use crate::configs::app_startup::username_set::UsernameSet; + use crate::http_server::endpoints::tts::enqueue_infer_tts_handler::enqueue_infer_tts_handler::{get_rate_limiter_type, RateLimiterType}; + + fn build_username_set() -> UsernameSet { + UsernameSet::from_comma_separated("ai_streamer") + } + + #[test] + fn test_logged_out() { + let rate_limiter = get_rate_limiter_type(None, &build_username_set(), false, false, false); + assert_eq!(rate_limiter, RateLimiterType::LoggedOut); + } + + #[test] + fn test_logged_in() { + let username = Some("not_ai_streamer"); + let rate_limiter = get_rate_limiter_type(username, &build_username_set(), false, false, false); + assert_eq!(rate_limiter, RateLimiterType::LoggedIn); + } + + #[test] + fn test_ai_streamer() { + let username = Some("ai_streamer"); + let rate_limiter = get_rate_limiter_type(username, &build_username_set(), false, false, false); + assert_eq!(rate_limiter, RateLimiterType::ApiAiStreamer); + } + } +} From 9ab8e5221190980666a1510fdf699171149bfcba Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Wed, 13 Dec 2023 16:58:37 -0500 Subject: [PATCH 029/124] more rate limiter fixes --- .../app_startup/redis_rate_limiters.rs | 28 +++++++++++++++++++ .../animation/enqueue_face_animation.rs | 16 +++++++---- .../media_uploads/common/handle_upload.rs | 21 +++++++------- .../enqueue_voice_conversion_inference.rs | 15 ++++++---- .../inference/enqueue_tts_request.rs | 17 ++++++----- .../voice_dataset_samples/upload_zs_sample.rs | 18 +++++++----- .../voice_designer/voices/create_voice.rs | 16 +++++++---- .../w2l/enqueue_infer_w2l_with_uploads.rs | 15 ++++++---- .../web/storyteller_web/src/server_state.rs | 6 ++++ 9 files changed, 103 insertions(+), 49 deletions(-) diff --git a/crates/service/web/storyteller_web/src/configs/app_startup/redis_rate_limiters.rs b/crates/service/web/storyteller_web/src/configs/app_startup/redis_rate_limiters.rs index 1dc2b4d5cd..3aa3df32cf 100644 --- a/crates/service/web/storyteller_web/src/configs/app_startup/redis_rate_limiters.rs +++ b/crates/service/web/storyteller_web/src/configs/app_startup/redis_rate_limiters.rs @@ -91,6 +91,32 @@ pub fn configure_redis_rate_limiters(common_env: &CommonEnv) -> AnyhowResult AnyhowResult &server_state.redis_rate_limiters.logged_out, - Some(ref user) => { - if user.role.is_banned { - return Err(EnqueueFaceAnimationError::NotAuthorized); - } - &server_state.redis_rate_limiters.logged_in - }, + Some(ref _user) => &server_state.redis_rate_limiters.logged_in }; if let Err(_err) = rate_limiter.rate_limit_request(&http_request) { diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_uploads/common/handle_upload.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_uploads/common/handle_upload.rs index 2d79cab2e7..7fe2872d84 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/media_uploads/common/handle_upload.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_uploads/common/handle_upload.rs @@ -66,26 +66,25 @@ pub async fn handle_upload( UploadError::ServerError })?; + // ==================== BANNED USERS ==================== // + + if let Some(ref user) = maybe_user_session { + if user.is_banned { + return Err(UploadError::NotAuthorized); + } + } + // ==================== RATE LIMIT ==================== // let rate_limiter = match maybe_user_session { - None => &server_state.redis_rate_limiters.logged_out, - Some(ref user) => { - if user.is_banned { - return Err(UploadError::NotAuthorized); - } - &server_state.redis_rate_limiters.logged_in - }, + None => &server_state.redis_rate_limiters.file_upload_logged_out, + Some(ref _session) => &server_state.redis_rate_limiters.file_upload_logged_in, }; if let Err(_err) = rate_limiter.rate_limit_request(&http_request) { return Err(UploadError::RateLimited); } - if let Err(_err) = server_state.redis_rate_limiters.model_upload.rate_limit_request(&http_request) { - return Err(UploadError::RateLimited); - } - // ==================== READ MULTIPART REQUEST ==================== // let upload_media_request = drain_multipart_request(multipart_payload) diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_conversion/inference/enqueue_voice_conversion_inference.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_conversion/inference/enqueue_voice_conversion_inference.rs index 22131729c0..7be7cec00d 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_conversion/inference/enqueue_voice_conversion_inference.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_conversion/inference/enqueue_voice_conversion_inference.rs @@ -205,17 +205,20 @@ pub async fn enqueue_voice_conversion_inference_handler( get_request_header_optional(&http_request, ROUTING_TAG_HEADER_NAME) .map(|routing_tag| routing_tag.trim().to_string()); + // ==================== BANNED USERS ==================== // + + if let Some(ref user) = maybe_user_session { + if user.role.is_banned { + return Err(EnqueueVoiceConversionInferenceError::NotAuthorized); + } + } + // ==================== RATE LIMIT ==================== // if !disable_rate_limiter { let mut rate_limiter = match maybe_user_session { None => &server_state.redis_rate_limiters.logged_out, - Some(ref user) => { - if user.role.is_banned { - return Err(EnqueueVoiceConversionInferenceError::NotAuthorized); - } - &server_state.redis_rate_limiters.logged_in - }, + Some(ref _session) => &server_state.redis_rate_limiters.logged_in }; // TODO/TEMP diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/inference/enqueue_tts_request.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/inference/enqueue_tts_request.rs index 41adb52569..7e09f40782 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/inference/enqueue_tts_request.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/inference/enqueue_tts_request.rs @@ -1,7 +1,6 @@ #![forbid(unused_imports)] #![forbid(unused_mut)] #![forbid(unused_variables)] -use utoipa::ToSchema; use std::fmt::Debug; use std::sync::Arc; @@ -12,6 +11,7 @@ use actix_web::http::StatusCode; use log::warn; use serde::Deserialize; use serde::Serialize; +use utoipa::ToSchema; use enums::by_table::generic_inference_jobs::inference_category::InferenceCategory; use enums::by_table::generic_inference_jobs::inference_model_type::InferenceModelType; @@ -153,16 +153,19 @@ pub async fn enqueue_tts_request( |routing_tag| routing_tag.trim().to_string() ); + // ==================== BANNED USERS ==================== // + + if let Some(ref user) = maybe_user_session { + if user.role.is_banned { + return Err(EnqueueTTSRequestError::NotAuthorized); + } + } + // ==================== RATE LIMIT ==================== // let rate_limiter = match maybe_user_session { None => &server_state.redis_rate_limiters.logged_out, - Some(ref user) => { - if user.role.is_banned { - return Err(EnqueueTTSRequestError::NotAuthorized); - } - &server_state.redis_rate_limiters.logged_in - } + Some(ref _user) => &server_state.redis_rate_limiters.logged_in, }; if let Err(_err) = rate_limiter.rate_limit_request(&http_request) { diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voice_dataset_samples/upload_zs_sample.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voice_dataset_samples/upload_zs_sample.rs index 004d303f44..e89e18eca9 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voice_dataset_samples/upload_zs_sample.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voice_dataset_samples/upload_zs_sample.rs @@ -26,6 +26,7 @@ use tokens::tokens::zs_voice_dataset_samples::ZsVoiceDatasetSampleToken; use tokens::tokens::zs_voice_datasets::ZsVoiceDatasetToken; use crate::http_server::endpoints::media_uploads::common::drain_multipart_request::{drain_multipart_request, MediaSource}; +use crate::http_server::endpoints::media_uploads::common::upload_error::UploadError; use crate::server_state::ServerState; use crate::validations::validate_idempotency_token_format::validate_idempotency_token_format; @@ -111,16 +112,19 @@ pub async fn upload_zs_sample_handler( UploadSampleError::ServerError })?; + // ==================== BANNED USERS ==================== // + + if let Some(ref user) = maybe_user_session { + if user.is_banned { + return Err(UploadSampleError::NotAuthorized); + } + } + // ==================== RATE LIMIT ==================== // let rate_limiter = match maybe_user_session { - None => &server_state.redis_rate_limiters.logged_out, - Some(ref user) => { - if user.is_banned { - return Err(UploadSampleError::NotAuthorized); - } - &server_state.redis_rate_limiters.logged_in - }, + None => &server_state.redis_rate_limiters.file_upload_logged_out, + Some(ref _user) => &server_state.redis_rate_limiters.file_upload_logged_in, }; if let Err(_err) = rate_limiter.rate_limit_request(&http_request) { diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voices/create_voice.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voices/create_voice.rs index b47de2c732..6654843007 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voices/create_voice.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/voices/create_voice.rs @@ -30,6 +30,7 @@ use tokens::tokens::generic_inference_jobs::InferenceJobToken; use tokens::tokens::users::UserToken; use crate::configs::plans::get_correct_plan_for_session::get_correct_plan_for_session; +use crate::http_server::endpoints::media_uploads::common::upload_error::UploadError; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; use crate::server_state::ServerState; @@ -138,16 +139,19 @@ pub async fn create_voice_handler( |routing_tag| routing_tag.trim().to_string() ); + // ==================== BANNED USERS ==================== // + + if let Some(ref user) = maybe_user_session { + if user.role.is_banned { + return Err(EnqueueCreateVoiceRequestError::NotAuthorized); + } + } + // ==================== RATE LIMIT ==================== // let rate_limiter = match maybe_user_session { None => &server_state.redis_rate_limiters.logged_out, - Some(ref user) => { - if user.role.is_banned { - return Err(EnqueueCreateVoiceRequestError::NotAuthorized); - } - &server_state.redis_rate_limiters.logged_in - } + Some(ref _user) => &server_state.redis_rate_limiters.logged_in, }; if let Err(_err) = rate_limiter.rate_limit_request(&http_request) { diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/w2l/enqueue_infer_w2l_with_uploads.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/w2l/enqueue_infer_w2l_with_uploads.rs index eee83b0dcc..8eea038050 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/w2l/enqueue_infer_w2l_with_uploads.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/w2l/enqueue_infer_w2l_with_uploads.rs @@ -102,16 +102,19 @@ pub async fn enqueue_infer_w2l_with_uploads( InferW2lWithUploadError::ServerError })?; + // ==================== BANNED USERS ==================== // + + if let Some(ref user) = maybe_session { + if user.is_banned { + return Err(InferW2lWithUploadError::NotAuthorized); + } + } + // ==================== RATE LIMIT ==================== // let rate_limiter = match maybe_session { None => &server_state.redis_rate_limiters.logged_out, - Some(ref user) => { - if user.is_banned { - return Err(InferW2lWithUploadError::NotAuthorized); - } - &server_state.redis_rate_limiters.logged_in - }, + Some(ref _user) => &server_state.redis_rate_limiters.logged_in, }; if let Err(_err) = rate_limiter.rate_limit_request(&http_request) { diff --git a/crates/service/web/storyteller_web/src/server_state.rs b/crates/service/web/storyteller_web/src/server_state.rs index a8f86133e2..c7ba601993 100644 --- a/crates/service/web/storyteller_web/src/server_state.rs +++ b/crates/service/web/storyteller_web/src/server_state.rs @@ -149,6 +149,12 @@ pub struct RedisRateLimiters { /// A rate limiter for TTS and W2L uploads pub model_upload: RedisRateLimiter, + + /// For uploading files for voice conversion, face animator, etc. + pub file_upload_logged_out: RedisRateLimiter, + + /// For uploading files for voice conversion, face animator, etc. + pub file_upload_logged_in: RedisRateLimiter, } /// In-memory caches of several types. From b30c352d79bad5ad5a4b07bd219412455168ac69 Mon Sep 17 00:00:00 2001 From: saltacc Date: Wed, 13 Dec 2023 16:29:45 -0800 Subject: [PATCH 030/124] pass tests --- .../src/by_table/generic_synthetic_ids/id_category.rs | 9 +++++++-- .../media_files/media_file_origin_model_type.rs | 10 +++++++--- .../media_files/media_file_origin_product_category.rs | 7 ++++++- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/crates/_types/enums/src/by_table/generic_synthetic_ids/id_category.rs b/crates/_types/enums/src/by_table/generic_synthetic_ids/id_category.rs index 01bddb94dd..e5b2e90771 100644 --- a/crates/_types/enums/src/by_table/generic_synthetic_ids/id_category.rs +++ b/crates/_types/enums/src/by_table/generic_synthetic_ids/id_category.rs @@ -80,7 +80,7 @@ impl IdCategory { "zs_dataset" => Ok(Self::ZeroShotVoiceDataset), "zs_voice" => Ok(Self::ZeroShotVoiceEmbedding), "zs_tts_result" => Ok(Self::ZeroShotTtsResult), - "rerender" => Ok(Self::RerenderResult), + "rerender" => Ok(Self::RerenderResult), "model_weights" => Ok(Self::ModelWeights), _ => Err(format!("invalid value: {:?}", value)), } @@ -92,6 +92,7 @@ impl IdCategory { BTreeSet::from([ Self::MediaFile, Self::LipsyncAnimationResult, + Self::RerenderResult, Self::TtsResult, Self::VoiceConversionResult, Self::ZeroShotTtsResult, @@ -114,6 +115,7 @@ mod tests { fn test_serialization() { assert_serialization(IdCategory::MediaFile, "media_file"); assert_serialization(IdCategory::LipsyncAnimationResult, "lipsync_animation"); + assert_serialization(IdCategory::RerenderResult, "rerender"); assert_serialization(IdCategory::TtsResult, "tts_result"); assert_serialization(IdCategory::VoiceConversionResult, "voice_conversion"); assert_serialization(IdCategory::ZeroShotVoiceDataset, "zs_dataset"); @@ -126,6 +128,7 @@ mod tests { fn to_str() { assert_eq!(IdCategory::MediaFile.to_str(), "media_file"); assert_eq!(IdCategory::LipsyncAnimationResult.to_str(), "lipsync_animation"); + assert_eq!(IdCategory::RerenderResult.to_str(), "rerender"); assert_eq!(IdCategory::TtsResult.to_str(), "tts_result"); assert_eq!(IdCategory::VoiceConversionResult.to_str(), "voice_conversion"); assert_eq!(IdCategory::ZeroShotVoiceDataset.to_str(), "zs_dataset"); @@ -138,6 +141,7 @@ mod tests { fn from_str() { assert_eq!(IdCategory::from_str("media_file").unwrap(), IdCategory::MediaFile); assert_eq!(IdCategory::from_str("lipsync_animation").unwrap(), IdCategory::LipsyncAnimationResult); + assert_eq!(IdCategory::from_str("rerender").unwrap(), IdCategory::RerenderResult); assert_eq!(IdCategory::from_str("tts_result").unwrap(), IdCategory::TtsResult); assert_eq!(IdCategory::from_str("voice_conversion").unwrap(), IdCategory::VoiceConversionResult); assert_eq!(IdCategory::from_str("zs_dataset").unwrap(), IdCategory::ZeroShotVoiceDataset); @@ -150,9 +154,10 @@ mod tests { fn all_variants() { // Static check let mut variants = IdCategory::all_variants(); - assert_eq!(variants.len(), 8); + assert_eq!(variants.len(), 9); assert_eq!(variants.pop_first(), Some(IdCategory::MediaFile)); assert_eq!(variants.pop_first(), Some(IdCategory::LipsyncAnimationResult)); + assert_eq!(variants.pop_first(), Some(IdCategory::RerenderResult)); assert_eq!(variants.pop_first(), Some(IdCategory::TtsResult)); assert_eq!(variants.pop_first(), Some(IdCategory::VoiceConversionResult)); assert_eq!(variants.pop_first(), Some(IdCategory::ZeroShotTtsResult)); diff --git a/crates/_types/enums/src/by_table/media_files/media_file_origin_model_type.rs b/crates/_types/enums/src/by_table/media_files/media_file_origin_model_type.rs index a79930d8c6..fa75c7f791 100644 --- a/crates/_types/enums/src/by_table/media_files/media_file_origin_model_type.rs +++ b/crates/_types/enums/src/by_table/media_files/media_file_origin_model_type.rs @@ -60,7 +60,7 @@ impl MediaFileOriginModelType { "so_vits_svc" => Ok(Self::SoVitsSvc), "tacotron2" => Ok(Self::Tacotron2), "vall_e_x" => Ok(Self::VallEX), - "rerender" => Ok(Self::Rerender), + "rerender" => Ok(Self::Rerender), _ => Err(format!("invalid value: {:?}", value)), } } @@ -73,7 +73,8 @@ impl MediaFileOriginModelType { Self::SadTalker, Self::SoVitsSvc, Self::Tacotron2, - Self::VallEX + Self::VallEX, + Self::Rerender, ]) } } @@ -98,6 +99,7 @@ mod tests { assert_eq!(MediaFileOriginModelType::SoVitsSvc.to_str(), "so_vits_svc"); assert_eq!(MediaFileOriginModelType::Tacotron2.to_str(), "tacotron2"); assert_eq!(MediaFileOriginModelType::VallEX.to_str(), "vall_e_x"); + assert_eq!(MediaFileOriginModelType::Rerender.to_str(), "rerender"); } #[test] @@ -107,18 +109,20 @@ mod tests { assert_eq!(MediaFileOriginModelType::from_str("so_vits_svc").unwrap(), MediaFileOriginModelType::SoVitsSvc); assert_eq!(MediaFileOriginModelType::from_str("tacotron2").unwrap(), MediaFileOriginModelType::Tacotron2); assert_eq!(MediaFileOriginModelType::from_str("vall_e_x").unwrap(), MediaFileOriginModelType::VallEX); + assert_eq!(MediaFileOriginModelType::from_str("rerender").unwrap(), MediaFileOriginModelType::Rerender); assert!(MediaFileOriginModelType::from_str("foo").is_err()); } #[test] fn all_variants() { let mut variants = MediaFileOriginModelType::all_variants(); - assert_eq!(variants.len(), 5); + assert_eq!(variants.len(), 6); assert_eq!(variants.pop_first(), Some(MediaFileOriginModelType::RvcV2)); assert_eq!(variants.pop_first(), Some(MediaFileOriginModelType::SadTalker)); assert_eq!(variants.pop_first(), Some(MediaFileOriginModelType::SoVitsSvc)); assert_eq!(variants.pop_first(), Some(MediaFileOriginModelType::Tacotron2)); assert_eq!(variants.pop_first(), Some(MediaFileOriginModelType::VallEX)); + assert_eq!(variants.pop_first(), Some(MediaFileOriginModelType::Rerender)); assert_eq!(variants.pop_first(), None); } } diff --git a/crates/_types/enums/src/by_table/media_files/media_file_origin_product_category.rs b/crates/_types/enums/src/by_table/media_files/media_file_origin_product_category.rs index 5965f9b3a9..103bab0042 100644 --- a/crates/_types/enums/src/by_table/media_files/media_file_origin_product_category.rs +++ b/crates/_types/enums/src/by_table/media_files/media_file_origin_product_category.rs @@ -80,6 +80,7 @@ impl MediaFileOriginProductCategory { BTreeSet::from([ Self::FaceAnimator, Self::TextToSpeech, + Self::Rerender, Self::Unknown, Self::VoiceConversion, Self::ZeroShotVoice, @@ -102,6 +103,7 @@ mod tests { assert_serialization(MediaFileOriginProductCategory::Unknown, "unknown"); assert_serialization(MediaFileOriginProductCategory::VoiceConversion, "voice_conversion"); assert_serialization(MediaFileOriginProductCategory::ZeroShotVoice, "zs_voice"); + assert_serialization(MediaFileOriginProductCategory::Rerender, "rerender") } #[test] @@ -111,6 +113,7 @@ mod tests { assert_eq!(MediaFileOriginProductCategory::Unknown.to_str(), "unknown"); assert_eq!(MediaFileOriginProductCategory::VoiceConversion.to_str(), "voice_conversion"); assert_eq!(MediaFileOriginProductCategory::ZeroShotVoice.to_str(), "zs_voice"); + assert_eq!(MediaFileOriginProductCategory::Rerender.to_str(), "rerender"); } #[test] @@ -120,17 +123,19 @@ mod tests { assert_eq!(MediaFileOriginProductCategory::from_str("unknown").unwrap(), MediaFileOriginProductCategory::Unknown); assert_eq!(MediaFileOriginProductCategory::from_str("voice_conversion").unwrap(), MediaFileOriginProductCategory::VoiceConversion); assert_eq!(MediaFileOriginProductCategory::from_str("zs_voice").unwrap(), MediaFileOriginProductCategory::ZeroShotVoice); + assert_eq!(MediaFileOriginProductCategory::from_str("rerender").unwrap(), MediaFileOriginProductCategory::Rerender); } #[test] fn all_variants() { let mut variants = MediaFileOriginProductCategory::all_variants(); - assert_eq!(variants.len(), 5); + assert_eq!(variants.len(), 6); assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::FaceAnimator)); assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::TextToSpeech)); assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::Unknown)); assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::VoiceConversion)); assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::ZeroShotVoice)); + assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::Rerender)); assert_eq!(variants.pop_first(), None); } } From 0ed04839d3a36c0270905aa08a7c4ab8473ff35a Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Wed, 13 Dec 2023 20:27:04 -0500 Subject: [PATCH 031/124] takedown request --- _sql/actions/voice_conversion_models.sql | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/_sql/actions/voice_conversion_models.sql b/_sql/actions/voice_conversion_models.sql index 9fd7b4ee20..1c040d57da 100644 --- a/_sql/actions/voice_conversion_models.sql +++ b/_sql/actions/voice_conversion_models.sql @@ -371,7 +371,8 @@ where token IN ( 'vcm_xy97xcgnk9y6', 'vcm_a47wtfbsjrfc', 'vcm_kygenhbg5mgj', - 'vcm_s8gndv19yt7p' + 'vcm_s8gndv19yt7p', + 'vcm_ny9pj57w5eyh' ); From a25e9aba9115b0c462c3090564912b7c0376c770 Mon Sep 17 00:00:00 2001 From: Michael Chung Date: Wed, 13 Dec 2023 23:18:14 -0500 Subject: [PATCH 032/124] Seeding model weights --- .env | 2 +- Cargo.lock | 1 + crates/cli/dev_database_seed/Cargo.toml | 2 +- crates/cli/dev_database_seed/src/main.rs | 6 +- .../cli/dev_database_seed/src/seeding/mod.rs | 3 +- .../src/seeding/seed_model_weights.rs | 241 ++++++++++++++++++ 6 files changed, 251 insertions(+), 4 deletions(-) create mode 100644 crates/cli/dev_database_seed/src/seeding/seed_model_weights.rs diff --git a/.env b/.env index a39f1b1d8d..c41492d472 100644 --- a/.env +++ b/.env @@ -76,4 +76,4 @@ TTS_HIFIGAN_SUPERRES_VOCODER_MODEL_FILENAME=hifigan_superres_twilight_33000.pt # Development key. Permissible to check in. NEWRELIC_API_KEY=c402be1c4c4216ec83d0cfc0851520cfFFFFNRAL -#STORYTELLER_ROOT="/home/tensor/code/storyteller/" # Put this in .env-secrets so that not everyone gets this setting. +STORYTELLER_ROOT="/home/tensor/code/storyteller/" # Put this in .env-secrets so that not everyone gets this setting. diff --git a/Cargo.lock b/Cargo.lock index 25191d742f..2c3aad99e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1751,6 +1751,7 @@ dependencies = [ "mimetypes", "my-workspace-hack", "mysql_queries", + "rand 0.8.5", "sqlx", "storyteller_root", "tokens", diff --git a/crates/cli/dev_database_seed/Cargo.toml b/crates/cli/dev_database_seed/Cargo.toml index a771241cf5..a6e1bfc853 100644 --- a/crates/cli/dev_database_seed/Cargo.toml +++ b/crates/cli/dev_database_seed/Cargo.toml @@ -34,7 +34,7 @@ my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" } # External log = "0.4.14" clap = "2.34.0" # TODO: This is really out of date, but has conflicts when updated - +rand = "0.8.5" # Runtime # NB: We switched to Tokio from `async-std` for broader ecosystem support. tokio = { version = "1.34.0", features = ["macros"] } diff --git a/crates/cli/dev_database_seed/src/main.rs b/crates/cli/dev_database_seed/src/main.rs index 558478772e..6a2290bea5 100644 --- a/crates/cli/dev_database_seed/src/main.rs +++ b/crates/cli/dev_database_seed/src/main.rs @@ -7,7 +7,8 @@ use errors::AnyhowResult; use crate::bucket_clients::get_bucket_clients; use crate::cli_args::parse_cli_args; -use crate::seeding::model_weights::seed_weights; +use crate::seeding::model_weights::seed_weights; // V1 +use crate::seeding::seed_model_weights::seed_weights_files; // V2 v3 will come later on when everything is more conslidated and clear. use crate::seeding::seed_media_files::seed_media_files; use crate::seeding::tts_tacotron2::seed_tts_tacotron2; use crate::seeding::users::seed_user_accounts; @@ -60,6 +61,9 @@ pub async fn main() -> AnyhowResult<()> { seed_weights(&pool).await?; seed_tts_tacotron2(&pool, maybe_bucket_clients.as_ref()).await?; + + // should seed the weights with a few files for hanashi + seed_weights_files(&pool, maybe_bucket_clients.as_ref()).await?; info!("Done!"); Ok(()) diff --git a/crates/cli/dev_database_seed/src/seeding/mod.rs b/crates/cli/dev_database_seed/src/seeding/mod.rs index c1100805b6..7bc49a4b9a 100644 --- a/crates/cli/dev_database_seed/src/seeding/mod.rs +++ b/crates/cli/dev_database_seed/src/seeding/mod.rs @@ -3,4 +3,5 @@ pub mod seed_media_files; pub mod tts_tacotron2; pub mod users; pub mod voice_conversion; -pub mod zero_shot_tts; \ No newline at end of file +pub mod zero_shot_tts; +pub mod seed_model_weights; \ No newline at end of file diff --git a/crates/cli/dev_database_seed/src/seeding/seed_model_weights.rs b/crates/cli/dev_database_seed/src/seeding/seed_model_weights.rs new file mode 100644 index 0000000000..72ab9badd3 --- /dev/null +++ b/crates/cli/dev_database_seed/src/seeding/seed_model_weights.rs @@ -0,0 +1,241 @@ +use std::path::Path; + +use log::{ info, warn }; +use sqlx::{ MySql, Pool }; + +use buckets::{ public::{ media_files::bucket_file_path::MediaFileBucketPath, self }, private }; + +use filesys::file_read_bytes::file_read_bytes; +use filesys::file_size::file_size; +use filesys::path_to_string::path_to_string; +use hashing::sha256::sha256_hash_file::sha256_hash_file; +use mimetypes::mimetype_for_bytes::get_mimetype_for_bytes; +use mimetypes::mimetype_for_file::get_mimetype_for_file; + +use storyteller_root::get_seed_tool_data_root; +use tokens::tokens::users::UserToken; +use crate::bucket_clients::BucketClients; +use crate::seeding::users::HANASHI_USER_TOKEN; + +use enums::{ + by_table::model_weights::{ weights_category::WeightsCategory, weights_types::WeightsType }, + common::visibility::Visibility, +}; + +use rand::Rng; +use errors::{ anyhow, AnyhowResult }; +use mysql_queries::queries::model_weights::create_weight::{ + create_weight, + CreateModelWeightsArgs, + self, +}; +use tokens::tokens::model_weights::ModelWeightToken; + +pub async fn seed_weights_files( + mysql_pool: &Pool, + maybe_bucket_clients: Option<&BucketClients> +) -> AnyhowResult<()> { + info!("Seeding weights files..."); + + let seeded_weights = [ + ( + HANASHI_USER_TOKEN, + "m_21jxt406aattq2cna1xtgf5m4mjyy1", + WeightsType::LoRA, + WeightsCategory::ImageGeneration, + "Niji Mecha", + "models/imagegen/loRA/nijiMecha.safetensors", + ), + ( + HANASHI_USER_TOKEN, + "m_cxzabpxf88h10rshqraksxbqmhs412", + WeightsType::StableDiffusion15, + WeightsCategory::ImageGeneration, + "Niji Diffused Mix", + "models/imagegen/sd15/nijidiffusedmix_v40.safetensors", + ), + ( + HANASHI_USER_TOKEN, + "m_21jxt406aattq2cna1xtgf5m4mjyy9", + WeightsType::LoRA, + WeightsCategory::ImageGeneration, + "Niji Mecha", + "models/imagegen/loRA/nijiMecha.safetensors", + ), + ( + HANASHI_USER_TOKEN, + "m_cxzabpxf88h10rshqraksxbqmhs413", + WeightsType::StableDiffusion15, + WeightsCategory::ImageGeneration, + "Niji Diffused Mix", + "models/imagegen/sd15/nijidiffusedmix_v40.safetensors", + ), + ]; + + let seed_tool_data_root = get_seed_tool_data_root(); + + for ( + user_token, + weights_file_token, + weights_type, + weights_category, + model_name, + subdirectory_path, + ) in seeded_weights { + let user_token = UserToken::new_from_str(user_token); + // prepare the inputs for a model + let mut rng = rand::thread_rng(); + let n: u32 = rng.gen(); + + let model_weight_token = ModelWeightToken(format!("{}", n)); // random token + let model_weight_token = model_weight_token; + + let title = model_name; + let description = "This is a description"; + let description_rendered_html = "This is a description rendered html"; + let original_filename = "model.safetensors"; + let original_download_url = "https://example.com/model.safetensors"; + let thumbnail_token = format!("{}", n); + + let public_bucket_hash: String = weights_file_token.to_string(); + let public_bucket_prefix = weights_type.to_str(); + let public_bucket_extension = weights_category.to_str(); + + let cached_user_ratings_total_count = n.clone(); + let cached_user_ratings_positive_count = n.clone(); + let cached_user_ratings_negative_count = n.clone(); + let cached_user_ratings_ratio = 100.0 as f32; + let version = 1; + + // get the abs path of the weights file to upload. + let mut weight_file_path = seed_tool_data_root.clone(); + weight_file_path.push(subdirectory_path); + + let file_size_bytes = file_size(weight_file_path.clone())?; + let sha256_checksum = sha256_hash_file(weight_file_path.clone())?; + + let result = seed_model( + &mysql_pool, + &model_weight_token, + &user_token, + weights_type, + &weight_file_path, + maybe_bucket_clients + ).await; + + let create_model_weights_args = CreateModelWeightsArgs { + token: &model_weight_token, + weights_type: weights_type, // Assuming weights_type is defined elsewhere + weights_category: weights_category, // Assuming weights_category is defined elsewhere + title: title.to_string(), + maybe_thumbnail_token: Some(thumbnail_token), + description_markdown: description.to_string(), + description_rendered_html: description_rendered_html.to_string(), + creator_user_token: Some(&user_token), + creator_ip_address: "127.0.0.1", // Assuming the IP address is localhost + creator_set_visibility: Visibility::Public, // Assuming the visibility is public + maybe_last_update_user_token: None, // Assuming there is no last update user token + original_download_url: Some(original_download_url.to_string()), + original_filename: Some(original_filename.to_string()), + file_size_bytes: file_size_bytes as i32, // Assuming the file size is 0 + file_checksum_sha2: sha256_checksum.to_string(), // Assuming the file checksum is an empty string + private_bucket_hash: public_bucket_hash, + maybe_private_bucket_prefix: Some(public_bucket_prefix.to_string()), + maybe_private_bucket_extension: Some(public_bucket_extension.to_string()), + cached_user_ratings_total_count: cached_user_ratings_total_count, + cached_user_ratings_positive_count: cached_user_ratings_positive_count, + cached_user_ratings_negative_count: cached_user_ratings_negative_count, + maybe_cached_user_ratings_ratio: Some(cached_user_ratings_ratio), + version: version, + mysql_pool: &mysql_pool, // Assuming mysql_pool is defined elsewhere + }; + + create_weight(create_model_weights_args).await?; + + match result { + Ok(_) => info!("Seeded {:?}", weight_file_path), + Err(err) => + warn!( + r#" + Could not seed media file {} , {:?} : {:?} + (No worries: if there's a duplicate key error, we probably already + seeded the media file on a previous invocation!) + "#, + model_weight_token, + subdirectory_path, + err + ), + } + } + + Ok(()) +} +struct BucketDetails { + bucket_hash: String, + maybe_bucket_prefix: Option, + maybe_bucket_extension: Option, +} + +async fn seed_model( + mysql_pool: &Pool, + model_weight_token: &ModelWeightToken, + user_token: &UserToken, + weight_type: WeightsType, + weight_file_path: &Path, + maybe_bucket_clients: Option<&BucketClients> +) -> AnyhowResult<()> { + info!("Seeding Media file {:?} ...", weight_file_path); + // mutable variables + let mut bucket_hash = "NOT_UPLOADED_BY_SEED_TOOL".to_string(); + let mut maybe_bucket_prefix = ""; + let mut maybe_bucket_extension = ""; + + if let Some(bucket_clients) = maybe_bucket_clients { + let bucket_details = seed_file_to_bucket(weight_file_path, bucket_clients).await?; + bucket_hash = bucket_details.bucket_hash; + maybe_bucket_prefix = bucket_details.maybe_bucket_prefix.as_deref().unwrap(); + maybe_bucket_extension = bucket_details.maybe_bucket_extension.as_deref().unwrap(); + } + + Ok(()) +} + +async fn seed_file_to_bucket( + weight_file_path: &Path, + bucket_clients: &BucketClients +) -> AnyhowResult { + info!("Uploading weights file {:?} ...", weight_file_path); + + let maybe_bucket_prefix = Some("fakeyou_"); + + let maybe_bucket_extension = weight_file_path + .extension() + .map(|extension| extension.to_str()) + .flatten(); + // we should just have this be file bucket path and then we can use a file descriptor to turn it into a specific type of path + let bucket_location = MediaFileBucketPath::generate_new( + maybe_bucket_prefix, + maybe_bucket_extension + ); + + let bucket_path = path_to_string(bucket_location.to_full_object_pathbuf()); + + info!("Reading weights file: {:?}", weight_file_path); + + let bytes = file_read_bytes(weight_file_path)?; + let mimetype = get_mimetype_for_bytes(&bytes).unwrap_or("application/octet-stream"); + + info!("Uploading weights file to bucket path: {:?}", bucket_path); + + let _r = bucket_clients.public.upload_file_with_content_type( + &bucket_path, + bytes.as_ref(), + mimetype + ).await?; + + Ok(BucketDetails { + bucket_hash: bucket_location.get_object_hash().to_string(), + maybe_bucket_prefix: maybe_bucket_prefix.map(|s| s.to_string()), + maybe_bucket_extension: maybe_bucket_extension.map(|s| s.to_string()), + }) +} From aad6b4e30457cd516a5c9668af0673fda8a8da17 Mon Sep 17 00:00:00 2001 From: ArEnSc <6252325+ArEnSc@users.noreply.github.com> Date: Wed, 13 Dec 2023 23:21:55 -0500 Subject: [PATCH 033/124] Update .env --- .env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env b/.env index c41492d472..a39f1b1d8d 100644 --- a/.env +++ b/.env @@ -76,4 +76,4 @@ TTS_HIFIGAN_SUPERRES_VOCODER_MODEL_FILENAME=hifigan_superres_twilight_33000.pt # Development key. Permissible to check in. NEWRELIC_API_KEY=c402be1c4c4216ec83d0cfc0851520cfFFFFNRAL -STORYTELLER_ROOT="/home/tensor/code/storyteller/" # Put this in .env-secrets so that not everyone gets this setting. +#STORYTELLER_ROOT="/home/tensor/code/storyteller/" # Put this in .env-secrets so that not everyone gets this setting. From cf034a900e55e81c1b6d8ea38a73bc579903a8e2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 14 Dec 2023 04:27:36 +0000 Subject: [PATCH 034/124] Bump clap from 2.34.0 to 4.4.8 Bumps [clap](https://github.com/clap-rs/clap) from 2.34.0 to 4.4.8. - [Release notes](https://github.com/clap-rs/clap/releases) - [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md) - [Commits](https://github.com/clap-rs/clap/compare/v2.34.0...v4.4.8) --- updated-dependencies: - dependency-name: clap dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- Cargo.lock | 91 +++---------------- crates/cli/dev_database_seed/Cargo.toml | 2 +- crates/cli/dev_upload_media_file/Cargo.toml | 2 +- crates/cli/elasticsearch-cli/Cargo.toml | 2 +- crates/cli/lru-delete-models/Cargo.toml | 2 +- crates/cli/scrape_test/Cargo.toml | 2 +- .../service/job/email_sender_job/Cargo.toml | 2 +- .../service/job/tts_inference_job/Cargo.toml | 2 +- 8 files changed, 20 insertions(+), 85 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 19da97d557..3874e5e3bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -483,15 +483,6 @@ dependencies = [ "libc", ] -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi 0.3.9", -] - [[package]] name = "anstream" version = "0.6.4" @@ -684,17 +675,6 @@ dependencies = [ "url", ] -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi 0.3.9", -] - [[package]] name = "autocfg" version = "1.1.0" @@ -1098,21 +1078,6 @@ dependencies = [ "inout", ] -[[package]] -name = "clap" -version = "2.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" -dependencies = [ - "ansi_term", - "atty", - "bitflags 1.3.2", - "strsim 0.8.0", - "textwrap", - "unicode-width", - "vec_map", -] - [[package]] name = "clap" version = "4.4.8" @@ -1132,7 +1097,7 @@ dependencies = [ "anstream", "anstyle", "clap_lex", - "strsim 0.10.0", + "strsim", ] [[package]] @@ -1529,7 +1494,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim 0.10.0", + "strsim", "syn 1.0.109", ] @@ -1543,7 +1508,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim 0.10.0", + "strsim", "syn 1.0.109", ] @@ -1557,7 +1522,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim 0.10.0", + "strsim", "syn 2.0.39", ] @@ -1737,7 +1702,7 @@ name = "dev-database-seed" version = "0.0.1" dependencies = [ "buckets", - "clap 2.34.0", + "clap", "cloud_storage", "config", "easyenv", @@ -1763,7 +1728,7 @@ name = "dev-upload-media-file" version = "0.0.1" dependencies = [ "buckets", - "clap 2.34.0", + "clap", "cloud_storage", "config", "easyenv", @@ -2046,7 +2011,7 @@ name = "elasticsearch-cli" version = "0.0.1" dependencies = [ "buckets", - "clap 2.34.0", + "clap", "config", "easyenv", "elasticsearch", @@ -2102,7 +2067,7 @@ dependencies = [ "bootstrap", "buckets", "chrono", - "clap 2.34.0", + "clap", "cloud_storage", "concurrency", "config", @@ -2666,15 +2631,6 @@ dependencies = [ "unicode-segmentation", ] -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - [[package]] name = "hermit-abi" version = "0.3.3" @@ -3077,7 +3033,7 @@ version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" dependencies = [ - "hermit-abi 0.3.3", + "hermit-abi", "rustix", "windows-sys 0.48.0", ] @@ -3380,7 +3336,7 @@ dependencies = [ name = "lru-delete-models" version = "0.0.1" dependencies = [ - "clap 4.4.8", + "clap", "errors", "logging", "my-workspace-hack", @@ -3973,7 +3929,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.3.3", + "hermit-abi", "libc", ] @@ -5125,7 +5081,7 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" name = "scrape_test" version = "0.0.1" dependencies = [ - "clap 2.34.0", + "clap", "errors", "my-workspace-hack", "tokio", @@ -6006,12 +5962,6 @@ dependencies = [ "unicode-normalization", ] -[[package]] -name = "strsim" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" - [[package]] name = "strsim" version = "0.10.0" @@ -6331,15 +6281,6 @@ dependencies = [ "my-workspace-hack", ] -[[package]] -name = "textwrap" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width", -] - [[package]] name = "thiserror" version = "1.0.50" @@ -6763,7 +6704,7 @@ version = "0.0.1" dependencies = [ "anyhow", "chrono", - "clap 2.34.0", + "clap", "cloud_storage", "collections", "config", @@ -7184,12 +7125,6 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" -[[package]] -name = "vec_map" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" - [[package]] name = "version-sync" version = "0.9.5" diff --git a/crates/cli/dev_database_seed/Cargo.toml b/crates/cli/dev_database_seed/Cargo.toml index a6e1bfc853..b065225a7f 100644 --- a/crates/cli/dev_database_seed/Cargo.toml +++ b/crates/cli/dev_database_seed/Cargo.toml @@ -33,7 +33,7 @@ my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" } # External log = "0.4.14" -clap = "2.34.0" # TODO: This is really out of date, but has conflicts when updated +clap = "4.4.8" # TODO: This is really out of date, but has conflicts when updated rand = "0.8.5" # Runtime # NB: We switched to Tokio from `async-std` for broader ecosystem support. diff --git a/crates/cli/dev_upload_media_file/Cargo.toml b/crates/cli/dev_upload_media_file/Cargo.toml index 47d58a89c0..9d928ea9e1 100644 --- a/crates/cli/dev_upload_media_file/Cargo.toml +++ b/crates/cli/dev_upload_media_file/Cargo.toml @@ -29,7 +29,7 @@ tokens = { path = "../../_types/tokens" } my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" } # External -clap = "2.34.0" # TODO: This is really out of date, but has conflicts when updated +clap = "4.4.8" # TODO: This is really out of date, but has conflicts when updated log = "0.4.14" # Runtime diff --git a/crates/cli/elasticsearch-cli/Cargo.toml b/crates/cli/elasticsearch-cli/Cargo.toml index 7361ad74b6..9b0af1cde7 100644 --- a/crates/cli/elasticsearch-cli/Cargo.toml +++ b/crates/cli/elasticsearch-cli/Cargo.toml @@ -29,7 +29,7 @@ my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" } # External log = "0.4.14" -clap = "2.34.0" # TODO: This is really out of date, but has conflicts when updated +clap = "4.4.8" # TODO: This is really out of date, but has conflicts when updated strum = { version = "0.25", features = ["derive"] } # Runtime diff --git a/crates/cli/lru-delete-models/Cargo.toml b/crates/cli/lru-delete-models/Cargo.toml index eb08a399a3..082775d726 100644 --- a/crates/cli/lru-delete-models/Cargo.toml +++ b/crates/cli/lru-delete-models/Cargo.toml @@ -21,7 +21,7 @@ logging = { path = "../../lib/logging" } my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" } # External -clap = { version = "4.4.7", features = ["derive"] } +clap = { version = "4.4.8", features = ["derive"] } walkdir = "2.4.0" [dev-dependencies] diff --git a/crates/cli/scrape_test/Cargo.toml b/crates/cli/scrape_test/Cargo.toml index 36284d1f33..f68f20dc30 100644 --- a/crates/cli/scrape_test/Cargo.toml +++ b/crates/cli/scrape_test/Cargo.toml @@ -22,5 +22,5 @@ web_scrapers = { path = "../../lib/web_scrapers" } my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" } # External -clap = "2.34.0" # TODO: This is really out of date, but has conflicts when updated +clap = "4.4.8" # TODO: This is really out of date, but has conflicts when updated tokio = { version = "1.34.0", features = ["macros"] } diff --git a/crates/service/job/email_sender_job/Cargo.toml b/crates/service/job/email_sender_job/Cargo.toml index 733388d420..07db875a2e 100644 --- a/crates/service/job/email_sender_job/Cargo.toml +++ b/crates/service/job/email_sender_job/Cargo.toml @@ -47,7 +47,7 @@ my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" } # External anyhow = "1.0.75" chrono = { version = "0.4.22", features = ["serde"] } -clap = "2.34.0" # TODO: This is really out of date, but has conflicts when updated +clap = "4.4.8" # TODO: This is really out of date, but has conflicts when updated dotenv = "0.15.0" hostname = "0.3.1" lfu = "0.2.5" diff --git a/crates/service/job/tts_inference_job/Cargo.toml b/crates/service/job/tts_inference_job/Cargo.toml index 2d1f6fa732..02b6a01ed5 100644 --- a/crates/service/job/tts_inference_job/Cargo.toml +++ b/crates/service/job/tts_inference_job/Cargo.toml @@ -33,7 +33,7 @@ my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" } # External anyhow = "1.0.75" chrono = { version = "0.4.22", features = ["serde"] } -clap = "2.34.0" # TODO: This is really out of date, but has conflicts when updated +clap = "4.4.8" # TODO: This is really out of date, but has conflicts when updated dotenv = "0.15.0" hostname = "0.3.1" lfu = "0.2.5" From 2f971dda60e2b6705d6c3788ac12687d099a819b Mon Sep 17 00:00:00 2001 From: saltacc Date: Wed, 13 Dec 2023 21:17:44 -0800 Subject: [PATCH 035/124] add model downloading --- .../inference_category.rs | 18 ++--- .../generic_synthetic_ids/id_category.rs | 20 +++--- .../media_file_origin_product_category.rs | 20 +++--- .../generic_inference_args.rs | 10 +-- .../videofilter_payload.rs | 24 ++++++- .../web/get_inference_job_status.rs | 4 +- .../insert_media_file_from_rerender.rs | 4 +- .../src/queries/model_weights/get_weight.rs | 2 +- .../src/job/job_loop/process_single_job.rs | 6 +- .../videofilter/process_single_vf_job.rs | 61 +--------------- .../rerender_a_video/download_model_file.rs | 64 +++++++++++++++++ .../videofilter/rerender_a_video/mod.rs | 2 + .../rerender_a_video/process_job.rs | 70 +++++++++++++++---- .../rerender_a_video/validate_job.rs | 54 ++++++++------ .../animation/enqueue_rerender_animation.rs | 35 +++++++--- .../inference_job/get_inference_job_status.rs | 2 +- 16 files changed, 247 insertions(+), 149 deletions(-) create mode 100644 crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/download_model_file.rs diff --git a/crates/_types/enums/src/by_table/generic_inference_jobs/inference_category.rs b/crates/_types/enums/src/by_table/generic_inference_jobs/inference_category.rs index d1a420544b..19bf5a74c7 100644 --- a/crates/_types/enums/src/by_table/generic_inference_jobs/inference_category.rs +++ b/crates/_types/enums/src/by_table/generic_inference_jobs/inference_category.rs @@ -26,8 +26,8 @@ pub enum InferenceCategory { #[serde(rename = "voice_conversion")] VoiceConversion, - #[serde(rename = "rerender_a_video")] - RerenderAVideo, + #[serde(rename = "video_filter")] + VideoFilter, } // TODO(bt, 2022-12-21): This desperately needs MySQL integration tests! @@ -41,7 +41,7 @@ impl InferenceCategory { Self::LipsyncAnimation => "lipsync_animation", Self::TextToSpeech => "text_to_speech", Self::VoiceConversion => "voice_conversion", - Self::RerenderAVideo => "rerender_a_video", + Self::VideoFilter => "video_filter", } } @@ -50,7 +50,7 @@ impl InferenceCategory { "lipsync_animation" => Ok(Self::LipsyncAnimation), "text_to_speech" => Ok(Self::TextToSpeech), "voice_conversion" => Ok(Self::VoiceConversion), - "rerender_a_video" => Ok(Self::RerenderAVideo), + "video_filter" => Ok(Self::VideoFilter), _ => Err(format!("invalid value: {:?}", value)), } } @@ -62,7 +62,7 @@ impl InferenceCategory { Self::LipsyncAnimation, Self::TextToSpeech, Self::VoiceConversion, - Self::RerenderAVideo, + Self::VideoFilter, ]) } } @@ -77,7 +77,7 @@ mod tests { assert_serialization(InferenceCategory::LipsyncAnimation, "lipsync_animation"); assert_serialization(InferenceCategory::TextToSpeech, "text_to_speech"); assert_serialization(InferenceCategory::VoiceConversion, "voice_conversion"); - assert_serialization(InferenceCategory::RerenderAVideo, "rerender_a_video"); + assert_serialization(InferenceCategory::VideoFilter, "video_filter"); } #[test] @@ -85,7 +85,7 @@ mod tests { assert_eq!(InferenceCategory::LipsyncAnimation.to_str(), "lipsync_animation"); assert_eq!(InferenceCategory::TextToSpeech.to_str(), "text_to_speech"); assert_eq!(InferenceCategory::VoiceConversion.to_str(), "voice_conversion"); - assert_eq!(InferenceCategory::RerenderAVideo.to_str(), "rerender_a_video"); + assert_eq!(InferenceCategory::VideoFilter.to_str(), "video_filter"); } #[test] @@ -93,7 +93,7 @@ mod tests { assert_eq!(InferenceCategory::from_str("lipsync_animation").unwrap(), InferenceCategory::LipsyncAnimation); assert_eq!(InferenceCategory::from_str("text_to_speech").unwrap(), InferenceCategory::TextToSpeech); assert_eq!(InferenceCategory::from_str("voice_conversion").unwrap(), InferenceCategory::VoiceConversion); - assert_eq!(InferenceCategory::from_str("rerender_a_video").unwrap(), InferenceCategory::RerenderAVideo); + assert_eq!(InferenceCategory::from_str("video_filter").unwrap(), InferenceCategory::VideoFilter); } #[test] @@ -104,7 +104,7 @@ mod tests { assert_eq!(variants.pop_first(), Some(InferenceCategory::LipsyncAnimation)); assert_eq!(variants.pop_first(), Some(InferenceCategory::TextToSpeech)); assert_eq!(variants.pop_first(), Some(InferenceCategory::VoiceConversion)); - assert_eq!(variants.pop_first(), Some(InferenceCategory::RerenderAVideo)); + assert_eq!(variants.pop_first(), Some(InferenceCategory::VideoFilter)); assert_eq!(variants.pop_first(), None); // Generated check diff --git a/crates/_types/enums/src/by_table/generic_synthetic_ids/id_category.rs b/crates/_types/enums/src/by_table/generic_synthetic_ids/id_category.rs index e5b2e90771..c751d5f5cc 100644 --- a/crates/_types/enums/src/by_table/generic_synthetic_ids/id_category.rs +++ b/crates/_types/enums/src/by_table/generic_synthetic_ids/id_category.rs @@ -21,9 +21,9 @@ pub enum IdCategory { #[serde(rename = "lipsync_animation")] LipsyncAnimationResult, - // Results from rerender a video - #[serde(rename = "rerender")] - RerenderResult, + // Results from video filters + #[serde(rename = "video_filter")] + VideoFilterResult, /// Results from tacotron2 /// Applies for RVC and SVC @@ -66,7 +66,7 @@ impl IdCategory { Self::ZeroShotVoiceDataset => "zs_dataset", Self::ZeroShotVoiceEmbedding => "zs_voice", Self::ZeroShotTtsResult => "zs_tts_result", - Self::RerenderResult => "rerender", + Self::VideoFilterResult => "video_filter", Self::ModelWeights => "model_weights", } } @@ -80,7 +80,7 @@ impl IdCategory { "zs_dataset" => Ok(Self::ZeroShotVoiceDataset), "zs_voice" => Ok(Self::ZeroShotVoiceEmbedding), "zs_tts_result" => Ok(Self::ZeroShotTtsResult), - "rerender" => Ok(Self::RerenderResult), + "video_filter" => Ok(Self::VideoFilterResult), "model_weights" => Ok(Self::ModelWeights), _ => Err(format!("invalid value: {:?}", value)), } @@ -92,7 +92,7 @@ impl IdCategory { BTreeSet::from([ Self::MediaFile, Self::LipsyncAnimationResult, - Self::RerenderResult, + Self::VideoFilterResult, Self::TtsResult, Self::VoiceConversionResult, Self::ZeroShotTtsResult, @@ -115,7 +115,7 @@ mod tests { fn test_serialization() { assert_serialization(IdCategory::MediaFile, "media_file"); assert_serialization(IdCategory::LipsyncAnimationResult, "lipsync_animation"); - assert_serialization(IdCategory::RerenderResult, "rerender"); + assert_serialization(IdCategory::VideoFilterResult, "video_filter"); assert_serialization(IdCategory::TtsResult, "tts_result"); assert_serialization(IdCategory::VoiceConversionResult, "voice_conversion"); assert_serialization(IdCategory::ZeroShotVoiceDataset, "zs_dataset"); @@ -128,7 +128,7 @@ mod tests { fn to_str() { assert_eq!(IdCategory::MediaFile.to_str(), "media_file"); assert_eq!(IdCategory::LipsyncAnimationResult.to_str(), "lipsync_animation"); - assert_eq!(IdCategory::RerenderResult.to_str(), "rerender"); + assert_eq!(IdCategory::VideoFilterResult.to_str(), "video_filter"); assert_eq!(IdCategory::TtsResult.to_str(), "tts_result"); assert_eq!(IdCategory::VoiceConversionResult.to_str(), "voice_conversion"); assert_eq!(IdCategory::ZeroShotVoiceDataset.to_str(), "zs_dataset"); @@ -141,7 +141,7 @@ mod tests { fn from_str() { assert_eq!(IdCategory::from_str("media_file").unwrap(), IdCategory::MediaFile); assert_eq!(IdCategory::from_str("lipsync_animation").unwrap(), IdCategory::LipsyncAnimationResult); - assert_eq!(IdCategory::from_str("rerender").unwrap(), IdCategory::RerenderResult); + assert_eq!(IdCategory::from_str("video_filter").unwrap(), IdCategory::VideoFilterResult); assert_eq!(IdCategory::from_str("tts_result").unwrap(), IdCategory::TtsResult); assert_eq!(IdCategory::from_str("voice_conversion").unwrap(), IdCategory::VoiceConversionResult); assert_eq!(IdCategory::from_str("zs_dataset").unwrap(), IdCategory::ZeroShotVoiceDataset); @@ -157,7 +157,7 @@ mod tests { assert_eq!(variants.len(), 9); assert_eq!(variants.pop_first(), Some(IdCategory::MediaFile)); assert_eq!(variants.pop_first(), Some(IdCategory::LipsyncAnimationResult)); - assert_eq!(variants.pop_first(), Some(IdCategory::RerenderResult)); + assert_eq!(variants.pop_first(), Some(IdCategory::VideoFilterResult)); assert_eq!(variants.pop_first(), Some(IdCategory::TtsResult)); assert_eq!(variants.pop_first(), Some(IdCategory::VoiceConversionResult)); assert_eq!(variants.pop_first(), Some(IdCategory::ZeroShotTtsResult)); diff --git a/crates/_types/enums/src/by_table/media_files/media_file_origin_product_category.rs b/crates/_types/enums/src/by_table/media_files/media_file_origin_product_category.rs index 103bab0042..e74da29ecf 100644 --- a/crates/_types/enums/src/by_table/media_files/media_file_origin_product_category.rs +++ b/crates/_types/enums/src/by_table/media_files/media_file_origin_product_category.rs @@ -39,9 +39,9 @@ pub enum MediaFileOriginProductCategory { #[serde(rename = "zs_voice")] ZeroShotVoice, - // Media files for Rerender - #[serde(rename = "rerender")] - Rerender, + // Media files for video filters + #[serde(rename = "video_filter")] + VideoFilter, } // TODO(bt, 2022-12-21): This desperately needs MySQL integration tests! @@ -58,7 +58,7 @@ impl MediaFileOriginProductCategory { Self::Unknown => "unknown", Self::VoiceConversion => "voice_conversion", Self::ZeroShotVoice => "zs_voice", - Self::Rerender => "rerender", + Self::VideoFilter => "video_filter", } } @@ -69,7 +69,7 @@ impl MediaFileOriginProductCategory { "unknown" => Ok(Self::Unknown), "voice_conversion" => Ok(Self::VoiceConversion), "zs_voice" => Ok(Self::ZeroShotVoice), - "rerender" => Ok(Self::Rerender), + "video_filter" => Ok(Self::VideoFilter), _ => Err(format!("invalid value: {:?}", value)), } } @@ -80,7 +80,7 @@ impl MediaFileOriginProductCategory { BTreeSet::from([ Self::FaceAnimator, Self::TextToSpeech, - Self::Rerender, + Self::VideoFilter, Self::Unknown, Self::VoiceConversion, Self::ZeroShotVoice, @@ -103,7 +103,7 @@ mod tests { assert_serialization(MediaFileOriginProductCategory::Unknown, "unknown"); assert_serialization(MediaFileOriginProductCategory::VoiceConversion, "voice_conversion"); assert_serialization(MediaFileOriginProductCategory::ZeroShotVoice, "zs_voice"); - assert_serialization(MediaFileOriginProductCategory::Rerender, "rerender") + assert_serialization(MediaFileOriginProductCategory::VideoFilter, "video_filter") } #[test] @@ -113,7 +113,7 @@ mod tests { assert_eq!(MediaFileOriginProductCategory::Unknown.to_str(), "unknown"); assert_eq!(MediaFileOriginProductCategory::VoiceConversion.to_str(), "voice_conversion"); assert_eq!(MediaFileOriginProductCategory::ZeroShotVoice.to_str(), "zs_voice"); - assert_eq!(MediaFileOriginProductCategory::Rerender.to_str(), "rerender"); + assert_eq!(MediaFileOriginProductCategory::VideoFilter.to_str(), "video_filter"); } #[test] @@ -123,7 +123,7 @@ mod tests { assert_eq!(MediaFileOriginProductCategory::from_str("unknown").unwrap(), MediaFileOriginProductCategory::Unknown); assert_eq!(MediaFileOriginProductCategory::from_str("voice_conversion").unwrap(), MediaFileOriginProductCategory::VoiceConversion); assert_eq!(MediaFileOriginProductCategory::from_str("zs_voice").unwrap(), MediaFileOriginProductCategory::ZeroShotVoice); - assert_eq!(MediaFileOriginProductCategory::from_str("rerender").unwrap(), MediaFileOriginProductCategory::Rerender); + assert_eq!(MediaFileOriginProductCategory::from_str("video_filter").unwrap(), MediaFileOriginProductCategory::VideoFilter); } #[test] @@ -135,7 +135,7 @@ mod tests { assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::Unknown)); assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::VoiceConversion)); assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::ZeroShotVoice)); - assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::Rerender)); + assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::VideoFilter)); assert_eq!(variants.pop_first(), None); } } diff --git a/crates/lib/mysql_queries/src/payloads/generic_inference_args/generic_inference_args.rs b/crates/lib/mysql_queries/src/payloads/generic_inference_args/generic_inference_args.rs index f34a4469c3..a67dd0bd91 100644 --- a/crates/lib/mysql_queries/src/payloads/generic_inference_args/generic_inference_args.rs +++ b/crates/lib/mysql_queries/src/payloads/generic_inference_args/generic_inference_args.rs @@ -37,9 +37,9 @@ pub enum InferenceCategoryAbbreviated { #[serde(alias = "voice_conversion")] VoiceConversion, - #[serde(rename = "rr")] // NB: DO NOT CHANGE. It could break live jobs. Renamed to be fewer bytes. - #[serde(alias = "rerender_a_video")] - RerenderAVideo, + #[serde(rename = "vf")] // NB: DO NOT CHANGE. It could break live jobs. Renamed to be fewer bytes. + #[serde(alias = "video_filter")] + VideoFilter, } #[derive(Serialize, Deserialize, Clone, Copy, Debug)] @@ -112,7 +112,7 @@ impl InferenceCategoryAbbreviated { InferenceCategory::LipsyncAnimation => Self::LipsyncAnimation, InferenceCategory::TextToSpeech => Self::TextToSpeech, InferenceCategory::VoiceConversion => Self::VoiceConversion, - InferenceCategory::RerenderAVideo => Self::RerenderAVideo, + InferenceCategory::VideoFilter => Self::VideoFilter, } } @@ -121,7 +121,7 @@ impl InferenceCategoryAbbreviated { Self::LipsyncAnimation => InferenceCategory::LipsyncAnimation, Self::TextToSpeech => InferenceCategory::TextToSpeech, Self::VoiceConversion => InferenceCategory::VoiceConversion, - Self::RerenderAVideo => InferenceCategory::RerenderAVideo, + Self::VideoFilter => InferenceCategory::VideoFilter, } } } diff --git a/crates/lib/mysql_queries/src/payloads/generic_inference_args/videofilter_payload.rs b/crates/lib/mysql_queries/src/payloads/generic_inference_args/videofilter_payload.rs index 12d316933f..1fbaeaab0a 100644 --- a/crates/lib/mysql_queries/src/payloads/generic_inference_args/videofilter_payload.rs +++ b/crates/lib/mysql_queries/src/payloads/generic_inference_args/videofilter_payload.rs @@ -1,3 +1,5 @@ +use tokens::tokens::model_weights::ModelWeightToken; + /// Video sources can be one of several: /// - F: media_files (todo) /// - U: media_uploads (legacy) @@ -32,5 +34,25 @@ pub struct RerenderArgs { #[serde(rename = "sd")] #[serde(skip_serializing_if = "Option::is_none")] - pub maybe_sd_model: Option, + pub maybe_sd_model_token: Option, + + #[serde(rename = "lora")] + #[serde(skip_serializing_if = "Option::is_none")] + pub maybe_lora_model_token: Option, + + #[serde(rename = "p")] + #[serde(skip_serializing_if = "Option::is_none")] + pub maybe_prompt: Option, + + #[serde(rename = "ap")] + #[serde(skip_serializing_if = "Option::is_none")] + pub maybe_a_prompt: Option, + + #[serde(rename = "np")] + #[serde(skip_serializing_if = "Option::is_none")] + pub maybe_n_prompt: Option, + + #[serde(rename = "se")] + #[serde(skip_serializing_if = "Option::is_none")] + pub maybe_seed: Option, } diff --git a/crates/lib/mysql_queries/src/queries/generic_inference/web/get_inference_job_status.rs b/crates/lib/mysql_queries/src/queries/generic_inference/web/get_inference_job_status.rs index 489ddd8391..e2a9b7be9c 100644 --- a/crates/lib/mysql_queries/src/queries/generic_inference/web/get_inference_job_status.rs +++ b/crates/lib/mysql_queries/src/queries/generic_inference/web/get_inference_job_status.rs @@ -178,7 +178,7 @@ fn raw_record_to_public_result(record: RawGenericInferenceJobStatus) -> GenericI InferenceCategory::LipsyncAnimation => Some("lipsync animation"), InferenceCategory::TextToSpeech => record.maybe_tts_model_title.as_deref(), InferenceCategory::VoiceConversion => record.maybe_voice_conversion_model_title.as_deref(), - InferenceCategory::RerenderAVideo => Some("rerender animation"), + InferenceCategory::VideoFilter => Some("Video Filter"), }; // NB: A bit of a hack. We store TTS results with a full path. @@ -187,7 +187,7 @@ fn raw_record_to_public_result(record: RawGenericInferenceJobStatus) -> GenericI InferenceCategory::LipsyncAnimation => (true, record.maybe_media_file_public_bucket_directory_hash.as_deref()), InferenceCategory::TextToSpeech => (false, record.maybe_tts_public_bucket_path.as_deref()), InferenceCategory::VoiceConversion => (true, record.maybe_voice_conversion_public_bucket_hash.as_deref()), - InferenceCategory::RerenderAVideo => (true, record.maybe_media_file_public_bucket_directory_hash.as_deref()), + InferenceCategory::VideoFilter => (true, record.maybe_media_file_public_bucket_directory_hash.as_deref()), }; // NB: We've moved voice conversion out of their own table and into media_files diff --git a/crates/lib/mysql_queries/src/queries/media_files/insert_media_file_from_rerender.rs b/crates/lib/mysql_queries/src/queries/media_files/insert_media_file_from_rerender.rs index c599a4fad0..b1adc3d6c3 100644 --- a/crates/lib/mysql_queries/src/queries/media_files/insert_media_file_from_rerender.rs +++ b/crates/lib/mysql_queries/src/queries/media_files/insert_media_file_from_rerender.rs @@ -55,7 +55,7 @@ pub async fn insert_media_file_from_rerender( let next_rerender_id = transactional_increment_generic_synthetic_id( &user_token, - IdCategory::RerenderResult, + IdCategory::VideoFilterResult, &mut transaction ).await?; @@ -67,7 +67,7 @@ pub async fn insert_media_file_from_rerender( let creator_set_visibility = args.job.creator_set_visibility.clone(); const ORIGIN_CATEGORY : MediaFileOriginCategory = MediaFileOriginCategory::Inference; - const ORIGIN_PRODUCT_CATEGORY : MediaFileOriginProductCategory = MediaFileOriginProductCategory::Rerender; + const ORIGIN_PRODUCT_CATEGORY : MediaFileOriginProductCategory = MediaFileOriginProductCategory::VideoFilter; const ORIGIN_MODEL_TYPE : MediaFileOriginModelType = MediaFileOriginModelType::Rerender; const MEDIA_TYPE : MediaFileType = MediaFileType::Video; diff --git a/crates/lib/mysql_queries/src/queries/model_weights/get_weight.rs b/crates/lib/mysql_queries/src/queries/model_weights/get_weight.rs index 050f4de251..01a128f9a7 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/get_weight.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/get_weight.rs @@ -33,7 +33,7 @@ pub struct RetrivedModelWeight { pub file_size_bytes: i32, pub file_checksum_sha2: String, pub private_bucket_hash: String, - pub maybe_private_bucket_prefix: Option, + pub maybe_private_bucket_prefix: Option, // TODO crossproduct rename these to public thx ^-^ pub maybe_private_bucket_extension: Option, pub cached_user_ratings_negative_count: u32, pub cached_user_ratings_positive_count: u32, diff --git a/crates/service/job/inference_job/src/job/job_loop/process_single_job.rs b/crates/service/job/inference_job/src/job/job_loop/process_single_job.rs index c7edcdbb7f..1aab84a477 100644 --- a/crates/service/job/inference_job/src/job/job_loop/process_single_job.rs +++ b/crates/service/job/inference_job/src/job/job_loop/process_single_job.rs @@ -16,7 +16,7 @@ use crate::job::job_loop::process_single_job_success_case::ProcessSingleJobSucce use crate::job::job_types::lipsync::process_single_lipsync_job::process_single_lipsync_job; use crate::job::job_types::tts::process_single_tts_job::process_single_tts_job; use crate::job::job_types::vc::process_single_vc_job::process_single_vc_job; -use crate::job::job_types::videofilter::process_single_vf_job::process_single_rr_job; +use crate::job::job_types::videofilter::process_single_vf_job::process_single_vf_job; use crate::job_dependencies::JobDependencies; pub async fn process_single_job( @@ -183,8 +183,8 @@ async fn do_process_single_job( InferenceCategory::VoiceConversion => { process_single_vc_job(job_dependencies, job).await? } - InferenceCategory::RerenderAVideo => { - process_single_rr_job(job_dependencies, job).await? + InferenceCategory::VideoFilter => { + process_single_vf_job(job_dependencies, job).await? } }; diff --git a/crates/service/job/inference_job/src/job/job_types/videofilter/process_single_vf_job.rs b/crates/service/job/inference_job/src/job/job_types/videofilter/process_single_vf_job.rs index 9d7cc0163c..076a723ef9 100644 --- a/crates/service/job/inference_job/src/job/job_types/videofilter/process_single_vf_job.rs +++ b/crates/service/job/inference_job/src/job/job_types/videofilter/process_single_vf_job.rs @@ -1,11 +1,4 @@ -use anyhow::anyhow; -use log::info; - -use mysql_queries::payloads::generic_inference_args::generic_inference_args::PolymorphicInferenceArgs::Rr; -use mysql_queries::payloads::generic_inference_args::videofilter_payload::VideofilterVideoSource; use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob; -use mysql_queries::queries::media_files::get_media_file::get_media_file; -use tokens::tokens::media_files::MediaFileToken; use crate::job::job_loop::job_success_result::JobSuccessResult; use crate::job::job_loop::process_single_job_error::ProcessSingleJobError; @@ -13,59 +6,7 @@ use crate::job::job_types::videofilter::rerender_a_video; use crate::job::job_types::videofilter::rerender_a_video::process_job::RerenderProcessJobArgs; use crate::job_dependencies::JobDependencies; -pub async fn process_single_rr_job(job_dependencies: &JobDependencies, job: &AvailableInferenceJob) -> Result { - // let maybe_inference_args = job.maybe_inference_args.as_ref().ok_or(ProcessSingleJobError::Other(anyhow!("Inference args not found")))?; - // - // let maybe_rerender_args = maybe_inference_args.args.as_ref().map(|args| match args { - // Rr(args) => Some(args), - // _ => None, - // }).flatten(); - // - // let rerender_args = match maybe_rerender_args { - // None => return Err(ProcessSingleJobError::Other(anyhow!("Rerender args not found"))), - // Some(args) => args, - // }; - // - // let videofilter_source = rerender_args.maybe_video_source.as_ref().ok_or(ProcessSingleJobError::Other(anyhow!("Video source not found")))?; - // - // let media_file_token = match videofilter_source { - // VideofilterVideoSource::F(token) => token, - // _ => return Err(ProcessSingleJobError::Other(anyhow!("Video source not found"))), - // }; - // - // let media_file_token = MediaFileToken::new_from_str(media_file_token); - // - // info!("media_file_token: {:?}", media_file_token); - // - // - // let media_file = match media_file_result { - // Ok(Some(result)) => result, - // Ok(None) => { - // return Err(ProcessSingleJobError::Other(anyhow!("Media file not found"))); - // } - // Err(e) => { - // return Err(ProcessSingleJobError::Other(anyhow!("Media file not found"))); - // } - // }; - - // info!("Source media upload file size (bytes): {}", &media_upload.original_file_size_bytes); - // info!("Source media upload duration (millis): {}", &media_upload.original_duration_millis); - // info!("Source media upload duration (seconds): {}", (media_upload.original_duration_millis as f32 / 1000.0)); - - - - // let job_success_result = match vc_model.model_type { - // VoiceConversionModelType::RvcV2 => { - // rvc_v2::process_job::process_job(RvcV2ProcessJobArgs { - // job_dependencies, - // job, - // vc_model: &vc_model, - // media_upload_token: &media_upload_token, - // media_upload: &media_upload, - // }).await? - // } - // }; - +pub async fn process_single_vf_job(job_dependencies: &JobDependencies, job: &AvailableInferenceJob) -> Result { let job_success_result = rerender_a_video::process_job::process_job( RerenderProcessJobArgs { job_dependencies, diff --git a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/download_model_file.rs b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/download_model_file.rs new file mode 100644 index 0000000000..42e4298f77 --- /dev/null +++ b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/download_model_file.rs @@ -0,0 +1,64 @@ +use std::path::PathBuf; + +use anyhow::anyhow; +use tempdir::TempDir; + +use buckets::public::media_files::bucket_file_path::MediaFileBucketPath; +use cloud_storage::bucket_client::BucketClient; +use jobs_common::job_progress_reporter::job_progress_reporter::JobProgressReporter; +use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob; +use mysql_queries::queries::model_weights::get_weight::RetrivedModelWeight; + +use crate::job::job_loop::process_single_job_error::ProcessSingleJobError; +use crate::util::maybe_download_file_from_bucket::{maybe_download_file_from_bucket, MaybeDownloadArgs}; +use crate::util::scoped_temp_dir_creator::ScopedTempDirCreator; + +pub struct ModelFile { + pub filesystem_path: PathBuf, +} + +pub async fn download_model_file( + model_record: &Option, + public_bucket_client: &BucketClient, + job_progress_reporter: &mut Box, + job: &AvailableInferenceJob, + temp_dir_creator: &ScopedTempDirCreator, + work_temp_dir: &TempDir, +) -> Result { + + let bucket_object_path; + + match model_record { + Some(model_record) => { + let model_bucket_path = + MediaFileBucketPath::from_object_hash( + &model_record.private_bucket_hash, + model_record.maybe_private_bucket_prefix.as_deref(), + model_record.maybe_private_bucket_extension.as_deref(), + ); + bucket_object_path = model_bucket_path.to_full_object_pathbuf(); + } + None => { + return Err(ProcessSingleJobError::from_anyhow_error( + anyhow!("could not find model file"))) + } + } + + let downloaded_filesystem_path = work_temp_dir.path().join("video.mp4"); + + maybe_download_file_from_bucket(MaybeDownloadArgs { + name_or_description_of_file: "video file", + final_filesystem_file_path: &downloaded_filesystem_path, + bucket_object_path: &bucket_object_path, + bucket_client: public_bucket_client, + job_progress_reporter, + job_progress_update_description: "downloading", + job_id: job.id.0, + scoped_tempdir_creator: &temp_dir_creator, + maybe_existing_file_minimum_size_required: None, + }).await?; + + Ok(ModelFile { + filesystem_path: downloaded_filesystem_path, + }) +} diff --git a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/mod.rs b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/mod.rs index 28c9dea48a..6b30de9473 100644 --- a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/mod.rs +++ b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/mod.rs @@ -4,3 +4,5 @@ mod download_video_file; mod rerender_inference_command; pub(crate) mod rerender_dependencies; mod categorize_error; +mod download_model_file; +mod download_model_file; diff --git a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/process_job.rs b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/process_job.rs index 705671b1c1..3cb8598978 100644 --- a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/process_job.rs +++ b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/process_job.rs @@ -16,13 +16,16 @@ use mimetypes::mimetype_for_file::get_mimetype_for_file; use mysql_queries::payloads::generic_inference_args::generic_inference_args::PolymorphicInferenceArgs::Rr; use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob; use mysql_queries::queries::media_files::insert_media_file_from_rerender::{insert_media_file_from_rerender, InsertArgs}; +use mysql_queries::queries::model_weights::get_weight::get_weight_by_token; use crate::job::job_loop::job_success_result::{JobSuccessResult, ResultEntity}; use crate::job::job_loop::process_single_job_error::ProcessSingleJobError; +use crate::job::job_types::videofilter::rerender_a_video::download_model_file::download_model_file; use crate::job::job_types::videofilter::rerender_a_video::download_video_file::download_video_file; use crate::job::job_types::videofilter::rerender_a_video::rerender_inference_command::InferenceArgs; use crate::job::job_types::videofilter::rerender_a_video::validate_job::validate_job; use crate::job_dependencies::JobDependencies; +use crate::util::maybe_download_file_from_bucket::{maybe_download_file_from_bucket, MaybeDownloadArgs}; /// The maximum that either width or height can be const MAX_DIMENSION : u32 = 1500; @@ -122,22 +125,69 @@ pub async fn process_job(args: RerenderProcessJobArgs<'_>) -> Result return Err(ProcessSingleJobError::Other(anyhow!("Rerender args not found"))), }; - let sd_model = rr_args.maybe_sd_model.as_ref().ok_or(ProcessSingleJobError::Other(anyhow!("SD model not found")))?; + + // =================== LOAD MODELS AND LORAS ==================== // + + let sd_model_token = rr_args.maybe_sd_model_token.as_ref().ok_or(ProcessSingleJobError::Other(anyhow!("SD model not found")))?; + + let retrieved_sd_record = get_weight_by_token( + sd_model_token, + false, + &deps.db.mysql_pool + ).await?; + + let model_path = download_model_file( + &retrieved_sd_record, + &args.job_dependencies.buckets.public_bucket_client, + &mut job_progress_reporter, + job, + &args.job_dependencies.fs.scoped_temp_dir_creator_for_work, + &work_temp_dir).await?; + + info!("Downloaded model file: {:?}", model_path.filesystem_path); + let sd_model = model_path.filesystem_path.to_str().unwrap().to_string(); + + let lora_path = match rr_args.maybe_lora_model_token.clone() { + Some(lora_model_token) => { + let retrieved_lora_record = get_weight_by_token( + &lora_model_token, + false, + &deps.db.mysql_pool + ).await?; + + let lora_path = download_model_file( + &retrieved_lora_record, + &args.job_dependencies.buckets.public_bucket_client, + &mut job_progress_reporter, + job, + &args.job_dependencies.fs.scoped_temp_dir_creator_for_work, + &work_temp_dir).await?; + + info!("Downloaded lora file: {:?}", lora_path.filesystem_path); + + Some(lora_path.filesystem_path) + } + None => None + }; + let sd_lora = match lora_path { + Some(lora_path) => Some(lora_path.to_str().unwrap().to_string()), + None => None + }; // ============== CREATE AND WRITE CONFIG TO DISK ============== // // create seed if not exists - // let seed = rr_args.seed.unwrap_or_else(|| rand::random::()); - let seed = rand::random::(); + let seed = rr_args.maybe_seed.unwrap_or_else(|| rand::random::()); let config = RerenderConfig { input: Some(usable_video_path.to_str().unwrap().to_string()), output: Some(output_video_fs_path.to_str().unwrap().to_string()), work_dir: Some(work_temp_dir.path().to_str().unwrap().to_string()), sd_model: Some(sd_model.to_string()), - prompt: Some("1girl, anime style, red hair".to_string()), - a_prompt: Some("1girl, 3d, realistic, read hair".to_string()), - n_prompt: Some("Bad quality, low quality, photo, artifacts, watermark, signature, faceless".to_string()), + lora_path: sd_lora, + prompt: rr_args.maybe_prompt.clone(), + a_prompt: rr_args.maybe_a_prompt.clone(), + n_prompt: rr_args.maybe_n_prompt.clone(), seed: Some(seed as i64), ..RerenderConfig::new() }; @@ -170,14 +220,6 @@ pub async fn process_job(args: RerenderProcessJobArgs<'_>) -> Result { - // warn!("Face not detected in source image"); - // error = ProcessSingleJobError::FaceDetectionFailure; - // } - // _ => {} - // } } safe_delete_temp_file(&video_path.filesystem_path); diff --git a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/validate_job.rs b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/validate_job.rs index dd9bc75c2f..6a1856899c 100644 --- a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/validate_job.rs +++ b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/validate_job.rs @@ -3,12 +3,18 @@ use anyhow::anyhow; use mysql_queries::payloads::generic_inference_args::generic_inference_args::{InferenceCategoryAbbreviated, PolymorphicInferenceArgs}; use mysql_queries::payloads::generic_inference_args::videofilter_payload::{VideofilterVideoSource}; use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob; +use tokens::tokens::model_weights::ModelWeightToken; use crate::job::job_loop::process_single_job_error::ProcessSingleJobError; pub struct JobArgs<'a> { pub video_source: &'a VideofilterVideoSource, - pub sd_model: &'a str, + pub sd_model_token: &'a ModelWeightToken, + pub lora_model_token: &'a Option, + pub prompt: &'a str, + pub a_prompt: &'a str, + pub n_prompt: &'a str, + pub seed: Option, } pub fn validate_job(job: &AvailableInferenceJob) -> Result { @@ -23,7 +29,7 @@ pub fn validate_job(job: &AvailableInferenceJob) -> Result {}, // Valid + Some(InferenceCategoryAbbreviated::VideoFilter) => {}, // Valid Some(category) => { return Err(ProcessSingleJobError::from_anyhow_error(anyhow!("wrong inference category for job: {:?}", category))); }, @@ -53,33 +59,41 @@ pub fn validate_job(job: &AvailableInferenceJob) -> Result args, None => { return Err(ProcessSingleJobError::from_anyhow_error(anyhow!("no sd model!"))); } }; + let prompt = match &inference_args.maybe_prompt { + Some(args) => args, + None => { + return Err(ProcessSingleJobError::from_anyhow_error(anyhow!("no prompt!"))); + } + }; - // let preprocess = match inference_args.maybe_preprocess { - // None => Some("full".to_string()), - // Some(Preprocess::F) => Some("full".to_string()), - // Some(Preprocess::EF) => Some("extfull".to_string()), - // Some(Preprocess::C) => Some("crop".to_string()), - // Some(Preprocess::EC) => Some("extcrop".to_string()), - // }; - // - // let enhancer = match inference_args.maybe_face_enhancer { - // None => None, - // Some(FaceEnhancer::G) => Some("gfpgan".to_string()), - // Some(FaceEnhancer::R) => Some("RestoreFormer".to_string()), - // }; - // - // let mut width = inference_args.maybe_resize_width; - // let mut height = inference_args.maybe_resize_height; + let a_prompt = match &inference_args.maybe_a_prompt { + Some(args) => args, + None => { + return Err(ProcessSingleJobError::from_anyhow_error(anyhow!("no a prompt!"))); + } + }; + + let n_prompt = match &inference_args.maybe_n_prompt { + Some(args) => args, + None => { + return Err(ProcessSingleJobError::from_anyhow_error(anyhow!("no n prompt!"))); + } + }; Ok(JobArgs { video_source, - sd_model, + sd_model_token, + lora_model_token: &inference_args.maybe_lora_model_token, + prompt, + a_prompt, + n_prompt, + seed: inference_args.maybe_seed, }) } diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/animation/enqueue_rerender_animation.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/animation/enqueue_rerender_animation.rs index d90caa3b8b..7cff133c25 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/animation/enqueue_rerender_animation.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/animation/enqueue_rerender_animation.rs @@ -20,6 +20,7 @@ use mysql_queries::payloads::generic_inference_args::videofilter_payload::{Reren use mysql_queries::queries::generic_inference::web::insert_generic_inference_job::{insert_generic_inference_job, InsertGenericInferenceArgs}; use tokens::tokens::generic_inference_jobs::InferenceJobToken; use tokens::tokens::media_files::MediaFileToken; +use tokens::tokens::model_weights::ModelWeightToken; use tokens::tokens::users::UserToken; use crate::configs::plans::get_correct_plan_for_session::get_correct_plan_for_session; @@ -38,8 +39,13 @@ const ROUTING_TAG_HEADER_NAME : &str = "routing-tag"; pub struct EnqueueRerenderAnimationRequest { uuid_idempotency_token: String, + prompt: Option, // prompt for the new video + a_prompt: Option, // prompt describing the old video + n_prompt: Option, // negative prompt video_source: Option, - sd_model: String, + sd_model_token: Option, + lora_model_token: Option, + seed: Option, creator_set_visibility: Option, } @@ -158,13 +164,15 @@ pub async fn enqueue_rerender_animation_handler( // TODO(bt): CHECK DATABASE FOR TOKENS! - let video_source: VideofilterVideoSource = { - if let Some(ref token) = request.video_source { - VideofilterVideoSource::media_file_token(token.as_str()) - } else { - return Err(EnqueueRerenderAnimationError::BadInput("video source not fully specified".to_string())); - } - }; + let video_source: VideofilterVideoSource = request.video_source + .as_ref() + .map(|token| VideofilterVideoSource::media_file_token(token.as_str())) + .ok_or_else(|| EnqueueRerenderAnimationError::BadInput("video source not fully specified".to_string()))?; + + let sd_model_token: ModelWeightToken = request.sd_model_token + .as_ref() + .map(|token| ModelWeightToken::new_from_str(token.as_str())) + .ok_or_else(|| EnqueueRerenderAnimationError::BadInput("sd model not fully specified".to_string()))?; let ip_address = get_request_ip(&http_request); @@ -178,14 +186,19 @@ pub async fn enqueue_rerender_animation_handler( let inference_args = RerenderArgs { maybe_video_source: Some(video_source), - maybe_sd_model: Some(request.sd_model.clone()), + maybe_sd_model_token: Some(sd_model_token), + maybe_lora_model_token: request.lora_model_token.clone(), + maybe_prompt: request.prompt.clone(), + maybe_a_prompt: request.a_prompt.clone(), + maybe_n_prompt: request.n_prompt.clone(), + maybe_seed: request.seed.clone(), }; info!("Creating rerender animation job record..."); let query_result = insert_generic_inference_job(InsertGenericInferenceArgs { uuid_idempotency_token: &request.uuid_idempotency_token, - inference_category: InferenceCategory::RerenderAVideo, + inference_category: InferenceCategory::VideoFilter, maybe_model_type: Some(InferenceModelType::RerenderAVideo), // NB: Model is static during inference maybe_model_token: None, // NB: Model is static during inference maybe_input_source_token: None, // TODO: Introduce a second foreign key ? @@ -193,7 +206,7 @@ pub async fn enqueue_rerender_animation_handler( maybe_raw_inference_text: None, // No text maybe_max_duration_seconds: None, maybe_inference_args: Some(GenericInferenceArgs { - inference_category: Some(InferenceCategoryAbbreviated::RerenderAVideo), + inference_category: Some(InferenceCategoryAbbreviated::VideoFilter), args: Some(PolymorphicInferenceArgs::Rr(inference_args)), }), maybe_creator_user_token: maybe_user_token.as_ref(), diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/inference_job/get_inference_job_status.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/inference_job/get_inference_job_status.rs index 5befd6c91e..071b3795a6 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/inference_job/get_inference_job_status.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/inference_job/get_inference_job_status.rs @@ -256,7 +256,7 @@ fn record_to_payload( .get_full_object_path_str() .to_string() } - InferenceCategory::RerenderAVideo => { + InferenceCategory::VideoFilter => { MediaFileBucketPath::from_object_hash( &result_details.public_bucket_location_or_hash, result_details.maybe_media_file_public_bucket_prefix.as_deref(), From a0375f10e21cc6bf89902620f3978c58c47e32aa Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Wed, 13 Dec 2023 10:48:58 -0500 Subject: [PATCH 036/124] Featured weights endpoint --- .../model_weights/weights_category.rs | 5 +- .../by_table/model_weights/weights_types.rs | 2 +- .../model_weights/list_weights_by_tokens.rs | 264 ++++++++++++++++++ .../src/queries/model_weights/mod.rs | 3 +- .../endpoints/weights/get_weight.rs | 4 +- .../weights/list_featured_weights.rs | 156 +++++++++++ .../src/http_server/endpoints/weights/mod.rs | 7 +- .../service/web/storyteller_web/src/routes.rs | 7 +- 8 files changed, 434 insertions(+), 14 deletions(-) create mode 100644 crates/lib/mysql_queries/src/queries/model_weights/list_weights_by_tokens.rs create mode 100644 crates/service/web/storyteller_web/src/http_server/endpoints/weights/list_featured_weights.rs diff --git a/crates/_types/enums/src/by_table/model_weights/weights_category.rs b/crates/_types/enums/src/by_table/model_weights/weights_category.rs index f6c4e6ed3f..f2b10e67d2 100644 --- a/crates/_types/enums/src/by_table/model_weights/weights_category.rs +++ b/crates/_types/enums/src/by_table/model_weights/weights_category.rs @@ -4,9 +4,8 @@ use std::collections::BTreeSet; use strum::EnumCount; #[cfg(test)] use strum::EnumIter; - - use utoipa::ToSchema; + #[cfg_attr(test, derive(EnumIter, EnumCount))] #[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize, ToSchema)] pub enum WeightsCategory { @@ -51,7 +50,7 @@ impl WeightsCategory { } impl_enum_display_and_debug_using_to_str!(WeightsCategory); impl_mysql_enum_coders!(WeightsCategory); - +impl_mysql_from_row!(WeightsCategory); #[cfg(test)] mod tests { diff --git a/crates/_types/enums/src/by_table/model_weights/weights_types.rs b/crates/_types/enums/src/by_table/model_weights/weights_types.rs index 1b6bbcb132..12f00955df 100644 --- a/crates/_types/enums/src/by_table/model_weights/weights_types.rs +++ b/crates/_types/enums/src/by_table/model_weights/weights_types.rs @@ -72,7 +72,7 @@ impl WeightsType { impl_enum_display_and_debug_using_to_str!(WeightsType); impl_mysql_enum_coders!(WeightsType); - +impl_mysql_from_row!(WeightsType); #[cfg(test)] mod tests { diff --git a/crates/lib/mysql_queries/src/queries/model_weights/list_weights_by_tokens.rs b/crates/lib/mysql_queries/src/queries/model_weights/list_weights_by_tokens.rs new file mode 100644 index 0000000000..f08a9534a9 --- /dev/null +++ b/crates/lib/mysql_queries/src/queries/model_weights/list_weights_by_tokens.rs @@ -0,0 +1,264 @@ +use chrono::{DateTime, Utc}; +use sqlx::{Acquire, FromRow, MySql, MySqlConnection, MySqlPool, QueryBuilder, Row}; +use sqlx::mysql::MySqlRow; + +use enums::by_table::model_weights::{ + weights_category::WeightsCategory, + weights_types::WeightsType, +}; +use enums::traits::mysql_from_row::MySqlFromRow; +use errors::AnyhowResult; +use tokens::tokens::model_weights::ModelWeightToken; +use tokens::tokens::users::UserToken; + +#[derive(Serialize)] +pub struct WeightsByTokensRecord { + pub token: ModelWeightToken, + + pub weights_type: WeightsType, + pub weights_category: WeightsCategory, + + pub title: String, + + pub maybe_thumbnail_token: Option, + + pub creator_user_token: UserToken, + pub creator_username: String, + pub creator_display_name: String, + pub creator_email_gravatar_hash: String, + + pub private_bucket_hash: String, + pub maybe_private_bucket_prefix: Option, + pub maybe_private_bucket_extension: Option, + + pub cached_user_ratings_total_count: u32, + pub cached_user_ratings_positive_count: u32, + pub cached_user_ratings_negative_count: u32, + pub maybe_cached_user_ratings_ratio: Option, + pub cached_user_ratings_last_updated_at: DateTime, + + pub created_at: DateTime, + pub updated_at: DateTime, + pub user_deleted_at: Option>, + pub mod_deleted_at: Option>, +} + +pub async fn list_weights_by_tokens( + mysql_pool: &MySqlPool, + weight_tokens: &[ModelWeightToken], + can_see_deleted: bool +) -> AnyhowResult> { + + let mut connection = mysql_pool.acquire().await?; + + let raw_weights: Vec = get_raw_weights_by_tokens(&mut connection, weight_tokens, can_see_deleted).await?; + + Ok(map_to_weights(raw_weights)) +} + +async fn get_raw_weights_by_tokens( + connection: &mut MySqlConnection, + weight_tokens: &[ModelWeightToken], + can_see_deleted: bool +) -> AnyhowResult> { + + let connection = connection.acquire().await?; + + let mut query_builder : QueryBuilder = if can_see_deleted { + QueryBuilder::new(r#" + SELECT + mw.token, + mw.title, + mw.weights_type, + mw.weights_category, + mw.maybe_thumbnail_token, + users.token as creator_user_token, + users.username as creator_username, + users.display_name as creator_display_name, + users.email_gravatar_hash as creator_email_gravatar_hash, + mw.private_bucket_hash, + mw.maybe_private_bucket_prefix, + mw.maybe_private_bucket_extension, + mw.cached_user_ratings_negative_count, + mw.cached_user_ratings_positive_count, + mw.cached_user_ratings_total_count, + mw.maybe_cached_user_ratings_ratio, + mw.cached_user_ratings_last_updated_at, + mw.created_at, + mw.updated_at, + mw.user_deleted_at, + mw.mod_deleted_at + FROM model_weights as mw + JOIN users + ON users.token = mw.creator_user_token + WHERE + mw.creator_set_visibility = "public" + AND mw.token IN ( + "#, + ) + + } else { + QueryBuilder::new(r#" + SELECT + mw.token, + mw.title, + mw.weights_type, + mw.weights_category, + mw.maybe_thumbnail_token, + users.token as creator_user_token, + users.username as creator_username, + users.display_name as creator_display_name, + users.email_gravatar_hash as creator_email_gravatar_hash, + mw.private_bucket_hash, + mw.maybe_private_bucket_prefix, + mw.maybe_private_bucket_extension, + mw.cached_user_ratings_negative_count, + mw.cached_user_ratings_positive_count, + mw.cached_user_ratings_total_count, + mw.maybe_cached_user_ratings_ratio, + mw.cached_user_ratings_last_updated_at, + mw.created_at, + mw.updated_at, + mw.user_deleted_at, + mw.mod_deleted_at + FROM model_weights as mw + JOIN users + ON users.token = mw.creator_user_token + WHERE + mw.creator_set_visibility = "public" + AND mw.user_deleted_at IS NULL + AND mw.mod_deleted_at IS NULL + AND mw.token IN ( + "# + ) + }; + + query_builder.push(token_predicate(weight_tokens)); + + query_builder.push(")"); + + let query = query_builder.build_query_as::(); + + let results = query.fetch_all(connection).await?; + + Ok(results) +} + +/// Return a comma-separated predicate, since SQLx does not yet support WHERE IN(?) for Vec, etc. +/// Issue: https://github.com/launchbadge/sqlx/issues/875 +fn token_predicate(tokens: &[ModelWeightToken]) -> String { + tokens.iter() + .map(|ty| ty.as_str()) + .map(|ty| format!("\"{}\"", ty)) + .collect::>() + .join(", ") +} + +fn map_to_weights(dataset:Vec) -> Vec { + let weights: Vec = dataset + .into_iter() + .map(|dataset: RawWeightJoinUser| { + WeightsByTokensRecord { + token: dataset.token, + title: dataset.title, + weights_type: dataset.weights_type, + weights_category: dataset.weights_category, + maybe_thumbnail_token: dataset.maybe_thumbnail_token, + + creator_user_token: dataset.creator_user_token, + creator_username:dataset.creator_username, + creator_display_name:dataset.creator_display_name, + creator_email_gravatar_hash:dataset.creator_email_gravatar_hash, + + private_bucket_hash: dataset.private_bucket_hash, + maybe_private_bucket_prefix: dataset.maybe_private_bucket_prefix, + maybe_private_bucket_extension: dataset.maybe_private_bucket_extension, + + cached_user_ratings_negative_count: dataset.cached_user_ratings_negative_count, + cached_user_ratings_positive_count: dataset.cached_user_ratings_positive_count, + cached_user_ratings_total_count: dataset.cached_user_ratings_total_count, + + maybe_cached_user_ratings_ratio: dataset.maybe_cached_user_ratings_ratio, + cached_user_ratings_last_updated_at: dataset.cached_user_ratings_last_updated_at, + + created_at: dataset.created_at, + updated_at: dataset.updated_at, + user_deleted_at: dataset.user_deleted_at, + mod_deleted_at: dataset.mod_deleted_at, + } + }).collect(); + + weights +} + + #[derive(Serialize)] + pub struct RawWeightJoinUser { + pub token: ModelWeightToken, + + pub weights_type: WeightsType, + pub weights_category: WeightsCategory, + + pub title: String, + + pub maybe_thumbnail_token: Option, + + pub creator_user_token: UserToken, + pub creator_username: String, + pub creator_display_name: String, + pub creator_email_gravatar_hash: String, + + pub private_bucket_hash: String, + pub maybe_private_bucket_prefix: Option, + pub maybe_private_bucket_extension: Option, + + pub cached_user_ratings_total_count: u32, + pub cached_user_ratings_positive_count: u32, + pub cached_user_ratings_negative_count: u32, + pub maybe_cached_user_ratings_ratio: Option, + pub cached_user_ratings_last_updated_at: DateTime, + + pub created_at: DateTime, + pub updated_at: DateTime, + pub user_deleted_at: Option>, + pub mod_deleted_at: Option>, +} + +// NB(bt,2023-12-05): There's an issue with type hinting in the `as` clauses with QueryBuilder (or +// raw query strings) and sqlx::FromRow, regardless of whether it is derived of manually +// implemented. Perhaps this will improve in the future, but for now manually constructed queries +// cannot have type hints, eg. the following: +// +// m.token as `token: tokens::tokens::media_files::MediaFileToken`, +// m.origin_category as `origin_category: enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory`, +// m.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`, +// +// This results in the automatic mapping not being able to be found by name (for macro derive), and +// in the manual case `row.try_get()` etc. won't have the correct column name (since the name is the +// full "as" clause). +impl FromRow<'_, MySqlRow> for RawWeightJoinUser { + fn from_row(row: &MySqlRow) -> Result { + Ok(Self { + token: ModelWeightToken::new(row.try_get("token")?), + weights_type: WeightsType::try_from_mysql_row(row, "weights_type")?, + weights_category: WeightsCategory::try_from_mysql_row(row, "weights_category")?, + title: row.try_get("title")?, + maybe_thumbnail_token: row.try_get("maybe_thumbnail_token")?, + creator_user_token: UserToken::new_from_str(row.try_get("creator_user_token")?), + creator_username: row.try_get("creator_username")?, + creator_display_name: row.try_get("creator_display_name")?, + creator_email_gravatar_hash: row.try_get("creator_email_gravatar_hash")?, + private_bucket_hash: row.try_get("private_bucket_hash")?, + maybe_private_bucket_prefix: row.try_get("maybe_private_bucket_prefix")?, + maybe_private_bucket_extension: row.try_get("maybe_private_bucket_extension")?, + cached_user_ratings_total_count: row.try_get("cached_user_ratings_total_count")?, + cached_user_ratings_positive_count: row.try_get("cached_user_ratings_positive_count")?, + cached_user_ratings_negative_count: row.try_get("cached_user_ratings_negative_count")?, + maybe_cached_user_ratings_ratio: row.try_get("maybe_cached_user_ratings_ratio")?, + cached_user_ratings_last_updated_at: row.try_get("cached_user_ratings_last_updated_at")?, + created_at: row.try_get("created_at")?, + updated_at: row.try_get("updated_at")?, + user_deleted_at: row.try_get("user_deleted_at")?, + mod_deleted_at: row.try_get("mod_deleted_at")?, + }) + } +} diff --git a/crates/lib/mysql_queries/src/queries/model_weights/mod.rs b/crates/lib/mysql_queries/src/queries/model_weights/mod.rs index 898685caa6..06aeec0264 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/mod.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/mod.rs @@ -1,7 +1,8 @@ pub mod create_weight; pub mod delete_weights; pub mod get_weight; -pub mod update_weight; +pub mod list_weights_by_tokens; pub mod list_weights_by_user; pub mod list_weights_query_builder; pub mod tests; +pub mod update_weight; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/get_weight.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/get_weight.rs index 02be96fef3..0b3f059aae 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/get_weight.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/get_weight.rs @@ -109,12 +109,12 @@ pub async fn get_weight_handler( } }; - let weight_token = path.weight_token.clone(); + let weight_token = ModelWeightToken::new_from_str(&path.weight_token); let creator_user_token = user_session.user_token.clone(); let is_mod = user_session.can_ban_users; let weight_lookup_result = get_weight_by_token( - &ModelWeightToken::new(weight_token.clone()), + &weight_token, is_mod, &server_state.mysql_pool, ).await; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/list_featured_weights.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/list_featured_weights.rs new file mode 100644 index 0000000000..33f921b722 --- /dev/null +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/list_featured_weights.rs @@ -0,0 +1,156 @@ +use std::sync::Arc; + +use actix_web::{HttpRequest, HttpResponse, web}; +use actix_web::error::ResponseError; +use actix_web::http::StatusCode; +use chrono::{DateTime, Utc}; +use log::{debug, error, warn}; +use r2d2_redis::redis::Commands; +use utoipa::ToSchema; + +use enums::by_table::model_weights::{ + weights_category::WeightsCategory, + weights_types::WeightsType, +}; +use mysql_queries::queries::model_weights::list_weights_by_tokens::list_weights_by_tokens; +use tokens::tokens::model_weights::ModelWeightToken; + +use crate::http_server::common_responses::user_details_lite::UserDetailsLight; +use crate::server_state::ServerState; + +#[derive(Serialize, ToSchema)] +pub struct ListFeaturedWeightsSuccessResponse { + pub success: bool, + pub weights: Vec, +} + +#[derive(Serialize, ToSchema)] +pub struct ModelWeightForList { + pub weight_token: ModelWeightToken, + + pub weights_type: WeightsType, + pub weights_category: WeightsCategory, + + pub title: String, + + pub maybe_thumbnail_token: Option, + + pub creator: UserDetailsLight, + + pub cached_user_ratings_total_count: u32, + pub cached_user_ratings_positive_count: u32, + pub cached_user_ratings_negative_count: u32, + pub maybe_cached_user_ratings_ratio: Option, + + pub created_at: DateTime, + pub updated_at: DateTime, +} + +/// The key we store featured weights tokens under +const REDIS_KEY : &str = "featured_weights_list"; + +#[derive(Debug, ToSchema)] +pub enum ListFeaturedWeightsError { + NotAuthorized, + ServerError, +} + +impl std::fmt::Display for ListFeaturedWeightsError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + +impl ResponseError for ListFeaturedWeightsError { + fn status_code(&self) -> StatusCode { + match *self { + ListFeaturedWeightsError::NotAuthorized => StatusCode::UNAUTHORIZED, + ListFeaturedWeightsError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, + } + } +} + +#[utoipa::path( + get, + path = "/v1/weights/list_featured", + responses( + (status = 200, description = "List Weights", body = ListFeaturedWeightsSuccessResponse), + (status = 401, description = "Not authorized", body = ListFeaturedWeightsError), + (status = 500, description = "Server error", body = ListFeaturedWeightsError), + ), +)] +pub async fn list_featured_weights_handler( + http_request: HttpRequest, + server_state: web::Data> +) -> Result { + + let mut redis = server_state.redis_pool.get() + .map_err(|err| { + error!("Could not obtain redis: {err}"); + ListFeaturedWeightsError::ServerError + })?; + + let token_list : Option = redis.get(REDIS_KEY) + .map_err(|err| { + error!("Could not get redis result: {err}"); + ListFeaturedWeightsError::ServerError + })?; + + let weight_tokens = token_list + .unwrap_or_else(|| "".to_string()) + .split(",") + .into_iter() + .map(|item| item.trim()) + .filter(|item| !item.is_empty()) + .map(|item| ModelWeightToken::new_from_str(item)) + .collect::>(); + + debug!("Weight tokens from Redis: {:?}", weight_tokens); + + let mut weights = Vec::new(); + + if !weight_tokens.is_empty() { + let query_results = + list_weights_by_tokens(&server_state.mysql_pool, &weight_tokens, false).await; + + weights = match query_results { + Ok(weights) => weights, + Err(e) => { + warn!("Query error: {:?}", e); + return Err(ListFeaturedWeightsError::ServerError); + } + }; + } + + // generate parse a response + let response = ListFeaturedWeightsSuccessResponse { + success: true, + weights: weights.into_iter() + .map(|w| ModelWeightForList { + weight_token: w.token, + title: w.title, + weights_type: w.weights_type, + weights_category: w.weights_category, + maybe_thumbnail_token: w.maybe_thumbnail_token, + creator: UserDetailsLight::from_db_fields( + &w.creator_user_token, + &w.creator_username, + &w.creator_display_name, + &w.creator_email_gravatar_hash + ), + cached_user_ratings_total_count: w.cached_user_ratings_total_count, + cached_user_ratings_positive_count: w.cached_user_ratings_positive_count, + cached_user_ratings_negative_count: w.cached_user_ratings_negative_count, + maybe_cached_user_ratings_ratio: w.maybe_cached_user_ratings_ratio, + created_at: w.created_at, + updated_at: w.updated_at, + }).collect::>(), + }; + + let body = serde_json::to_string(&response) + .map_err(|e| ListFeaturedWeightsError::ServerError)?; + + Ok(HttpResponse::Ok() + .content_type("application/json") + .body(body)) +} diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/mod.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/mod.rs index 3fbd1cb09d..f52604fe31 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/mod.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/mod.rs @@ -1,7 +1,8 @@ -pub mod get_weight; pub mod delete_weight; -pub mod update_weight; -pub mod list_weights_by_user; +pub mod get_weight; pub mod list_available_weights; +pub mod list_featured_weights; +pub mod list_weights_by_user; +pub mod update_weight; // pub mod create_weight; this is a private api call internally // pub mod drain_multipart_weights_request; \ No newline at end of file diff --git a/crates/service/web/storyteller_web/src/routes.rs b/crates/service/web/storyteller_web/src/routes.rs index 9dcdce3e35..0d13225c1a 100644 --- a/crates/service/web/storyteller_web/src/routes.rs +++ b/crates/service/web/storyteller_web/src/routes.rs @@ -156,6 +156,7 @@ use crate::http_server::endpoints::weights::get_weight::get_weight_handler; use crate::http_server::endpoints::weights::delete_weight::delete_weight_handler; use crate::http_server::endpoints::weights::update_weight::update_weight_handler; use crate::http_server::endpoints::weights::list_available_weights::list_available_weights_handler; +use crate::http_server::endpoints::weights::list_featured_weights::list_featured_weights_handler; use crate::http_server::endpoints::weights::list_weights_by_user::list_weights_by_user_handler; @@ -1265,9 +1266,7 @@ fn add_weights_routes(app: App) -> App .route(web::delete().to(delete_weight_handler)) ) .route("/by_user/{username}", web::get().to(list_weights_by_user_handler)) - .route( - "/list", - web::get().to(list_available_weights_handler) - ) + .route("/list", web::get().to(list_available_weights_handler)) + .route("/list_featured", web::get().to(list_featured_weights_handler)) ) } From faff80fcc64747cd56d71e9cc9ab380f2341e17b Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Thu, 14 Dec 2023 03:20:47 -0500 Subject: [PATCH 037/124] deterministic RNGs for tests --- Cargo.lock | 1 + crates/_types/tokens/Cargo.toml | 4 +- crates/_types/tokens/src/deterministic_rng.rs | 43 +++++++++++++++++++ crates/_types/tokens/src/lib.rs | 1 + crates/_types/tokens/src/macros.rs | 35 +++++++++++++++ .../tokens/tests/media_file_token_tests.rs | 24 +++++++++++ .../weights/list_featured_weights.rs | 1 - 7 files changed, 107 insertions(+), 2 deletions(-) create mode 100644 crates/_types/tokens/src/deterministic_rng.rs diff --git a/Cargo.lock b/Cargo.lock index 19da97d557..af9894f874 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6442,6 +6442,7 @@ name = "tokens" version = "0.0.1" dependencies = [ "my-workspace-hack", + "once_cell", "rand 0.8.5", "serde", "serde_derive", diff --git a/crates/_types/tokens/Cargo.toml b/crates/_types/tokens/Cargo.toml index 581f8c65de..94152dee1b 100644 --- a/crates/_types/tokens/Cargo.toml +++ b/crates/_types/tokens/Cargo.toml @@ -25,7 +25,9 @@ serde = "1.0.125" serde_derive = "1.0.125" # Random -rand = "0.8.5" +rand = { version = "0.8.5", features = ["std_rng"] } + +once_cell = { version = "1.18.0", features = [] } sqlx = { version = "0.7.2", features = [ "mysql", "runtime-tokio", "tls-rustls", "chrono" ] } sqlx-core = { version = "0.7.2" } diff --git a/crates/_types/tokens/src/deterministic_rng.rs b/crates/_types/tokens/src/deterministic_rng.rs new file mode 100644 index 0000000000..90ad47f5ab --- /dev/null +++ b/crates/_types/tokens/src/deterministic_rng.rs @@ -0,0 +1,43 @@ +use std::sync::{Arc, LockResult, RwLock, RwLockWriteGuard}; + +use once_cell::sync::Lazy; +use rand::rngs::StdRng; +use rand::SeedableRng; + +// FIXME(bt,2023-12-14): Is this threadsafe? Looks like it should be fine. +/// Only use this in tests (and dev seed tools), never in production! +#[derive(Clone)] +pub struct DeterministicRng { + rng : Arc> +} + +impl DeterministicRng { + pub fn get_instance() -> LockResult> { + static DETERMINISTIC_RNG : Lazy>> = Lazy::new(|| { + Arc::new(RwLock::new(DeterministicRng::new())) + }); + + DETERMINISTIC_RNG.write() + } + + fn new() -> Self { + Self { + rng: Arc::new(RwLock::new(StdRng::seed_from_u64(0))) + } + } + + /// Reset the deterministic RNG's seed. + pub fn reset_rng(&self) { + match self.rng.write() { + Err(err) => panic!(format!("test panic due to rng failure {err}")), + Ok(mut lock) => { + *lock = StdRng::seed_from_u64(0); + } + } + } + + /// Grab the deterministic RNG + pub fn get_rng(&self) -> LockResult>{ + self.rng.write() + } +} diff --git a/crates/_types/tokens/src/lib.rs b/crates/_types/tokens/src/lib.rs index df6e81b4f2..b220bdb751 100644 --- a/crates/_types/tokens/src/lib.rs +++ b/crates/_types/tokens/src/lib.rs @@ -49,6 +49,7 @@ pub(crate) static MINIMUM_CHARACTER_ENTROPY : usize = 8; #[macro_use] mod macros; +pub (crate) mod deterministic_rng; pub (crate) mod prefixes; pub mod tokens; diff --git a/crates/_types/tokens/src/macros.rs b/crates/_types/tokens/src/macros.rs index 5964b6109a..4df28db41a 100644 --- a/crates/_types/tokens/src/macros.rs +++ b/crates/_types/tokens/src/macros.rs @@ -60,6 +60,41 @@ macro_rules! impl_crockford_generator { $t(token) } + /// Constructor for a new token to be used **DETERMINISTICALLY** in tests and seeding. + /// This will not use a real RNG, so do not use in production code! + /// Once called, it will output the same random numbers in sequence. + pub fn reset_rng_for_testing_and_dev_seeding_never_use_in_production_seriously() { + let deterministic = crate::deterministic_rng::DeterministicRng::get_instance().expect("tests should not fail due to mutex"); + deterministic.reset_rng(); + } + + /// Constructor for a new token to be used **DETERMINISTICALLY** in tests and seeding. + /// This will not use a real RNG, so do not use in production code! + /// Once called, it will output the same random numbers in sequence. + pub fn generate_for_testing_and_dev_seeding_never_use_in_production_seriously() -> Self { + use rand::Rng; + + // FIXME(bt,2023-12-14): This is bad error handling. (Maybe panic if lock is poisoned?) + let deterministic = crate::deterministic_rng::DeterministicRng::get_instance().expect("tests should not fail due to mutex"); + let mut rng = deterministic.get_rng().expect("tests should not fail due to mutex"); + + let charset = Self::token_character_set(); + let entropy_length = Self::entropic_character_len(); + + let entropy_part: String = (0..entropy_length) + .map(|_| { + let idx = rng.gen_range(0..charset.len()); + charset[idx] as char + }) + .collect(); + + let token_prefix = Self::token_prefix(); + + let token = format!("{}{}", token_prefix, entropy_part); + + $t(token) + } + #[inline] pub fn entropy_suffix(&self) -> &str { use crate::prefixes::PrefixGenerator; diff --git a/crates/_types/tokens/tests/media_file_token_tests.rs b/crates/_types/tokens/tests/media_file_token_tests.rs index dc09692485..9a8704e1b2 100644 --- a/crates/_types/tokens/tests/media_file_token_tests.rs +++ b/crates/_types/tokens/tests/media_file_token_tests.rs @@ -21,6 +21,30 @@ mod interface { assert!(token.to_string().starts_with("m_")); } + #[test] + fn generate_for_testing_and_dev_seeding_never_use_in_production_seriously_1() { + MediaFileToken::reset_rng_for_testing_and_dev_seeding_never_use_in_production_seriously(); + assert_eq!(MediaFileToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously().as_str(), "m_q8sz47gmfw2zx02snrbz88ns9m16ab"); + assert_eq!(MediaFileToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously().as_str(), "m_ma1xetxrwbh39vg639a9zrq8b9wk6h"); + assert_eq!(MediaFileToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously().as_str(), "m_4tswec8z27wnm01njypx4vmfhgj41e"); + } + + #[test] + fn generate_for_testing_and_dev_seeding_never_use_in_production_seriously_2() { + MediaFileToken::reset_rng_for_testing_and_dev_seeding_never_use_in_production_seriously(); + assert_eq!(MediaFileToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously().as_str(), "m_q8sz47gmfw2zx02snrbz88ns9m16ab"); + assert_eq!(MediaFileToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously().as_str(), "m_ma1xetxrwbh39vg639a9zrq8b9wk6h"); + assert_eq!(MediaFileToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously().as_str(), "m_4tswec8z27wnm01njypx4vmfhgj41e"); + } + + #[test] + fn generate_for_testing_and_dev_seeding_never_use_in_production_seriously_3() { + MediaFileToken::reset_rng_for_testing_and_dev_seeding_never_use_in_production_seriously(); + assert_eq!(MediaFileToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously().as_str(), "m_q8sz47gmfw2zx02snrbz88ns9m16ab"); + assert_eq!(MediaFileToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously().as_str(), "m_ma1xetxrwbh39vg639a9zrq8b9wk6h"); + assert_eq!(MediaFileToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously().as_str(), "m_4tswec8z27wnm01njypx4vmfhgj41e"); + } + #[test] fn new() { let token = MediaFileToken::new("m_foo".to_string()); diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/list_featured_weights.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/list_featured_weights.rs index 33f921b722..87d75eed0f 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/list_featured_weights.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/list_featured_weights.rs @@ -122,7 +122,6 @@ pub async fn list_featured_weights_handler( }; } - // generate parse a response let response = ListFeaturedWeightsSuccessResponse { success: true, weights: weights.into_iter() From d447ad7d8676f1ea2f3e5304b9c3fed77278acd8 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Thu, 14 Dec 2023 03:49:58 -0500 Subject: [PATCH 038/124] deterministic test tokens it'd be good to use the same token values in tests, dev seed tools, etc. this should be a threadsafe, resettable, deterministic RNG --- crates/_types/tokens/src/deterministic_rng.rs | 4 +- crates/_types/tokens/src/macros.rs | 4 +- .../tokens/tests/media_file_token_tests.rs | 17 +++---- .../src/seeding/model_weights.rs | 44 ++++++++++--------- .../src/seeding/seed_model_weights.rs | 44 +++++++++---------- 5 files changed, 54 insertions(+), 59 deletions(-) diff --git a/crates/_types/tokens/src/deterministic_rng.rs b/crates/_types/tokens/src/deterministic_rng.rs index 90ad47f5ab..affd9fda00 100644 --- a/crates/_types/tokens/src/deterministic_rng.rs +++ b/crates/_types/tokens/src/deterministic_rng.rs @@ -27,11 +27,11 @@ impl DeterministicRng { } /// Reset the deterministic RNG's seed. - pub fn reset_rng(&self) { + pub fn reset_rng(&self, state: u64) { match self.rng.write() { Err(err) => panic!(format!("test panic due to rng failure {err}")), Ok(mut lock) => { - *lock = StdRng::seed_from_u64(0); + *lock = StdRng::seed_from_u64(state); } } } diff --git a/crates/_types/tokens/src/macros.rs b/crates/_types/tokens/src/macros.rs index 4df28db41a..44fc14d6df 100644 --- a/crates/_types/tokens/src/macros.rs +++ b/crates/_types/tokens/src/macros.rs @@ -63,9 +63,9 @@ macro_rules! impl_crockford_generator { /// Constructor for a new token to be used **DETERMINISTICALLY** in tests and seeding. /// This will not use a real RNG, so do not use in production code! /// Once called, it will output the same random numbers in sequence. - pub fn reset_rng_for_testing_and_dev_seeding_never_use_in_production_seriously() { + pub fn reset_rng_for_testing_and_dev_seeding_never_use_in_production_seriously(state: u64) { let deterministic = crate::deterministic_rng::DeterministicRng::get_instance().expect("tests should not fail due to mutex"); - deterministic.reset_rng(); + deterministic.reset_rng(state); } /// Constructor for a new token to be used **DETERMINISTICALLY** in tests and seeding. diff --git a/crates/_types/tokens/tests/media_file_token_tests.rs b/crates/_types/tokens/tests/media_file_token_tests.rs index 9a8704e1b2..722f89c0a5 100644 --- a/crates/_types/tokens/tests/media_file_token_tests.rs +++ b/crates/_types/tokens/tests/media_file_token_tests.rs @@ -23,23 +23,18 @@ mod interface { #[test] fn generate_for_testing_and_dev_seeding_never_use_in_production_seriously_1() { - MediaFileToken::reset_rng_for_testing_and_dev_seeding_never_use_in_production_seriously(); + // NB: Using the same reset seed will produce the same results each time + MediaFileToken::reset_rng_for_testing_and_dev_seeding_never_use_in_production_seriously(0); assert_eq!(MediaFileToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously().as_str(), "m_q8sz47gmfw2zx02snrbz88ns9m16ab"); assert_eq!(MediaFileToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously().as_str(), "m_ma1xetxrwbh39vg639a9zrq8b9wk6h"); assert_eq!(MediaFileToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously().as_str(), "m_4tswec8z27wnm01njypx4vmfhgj41e"); - } - - #[test] - fn generate_for_testing_and_dev_seeding_never_use_in_production_seriously_2() { - MediaFileToken::reset_rng_for_testing_and_dev_seeding_never_use_in_production_seriously(); + // NB: Same seed -> same tokens generated + MediaFileToken::reset_rng_for_testing_and_dev_seeding_never_use_in_production_seriously(0); assert_eq!(MediaFileToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously().as_str(), "m_q8sz47gmfw2zx02snrbz88ns9m16ab"); assert_eq!(MediaFileToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously().as_str(), "m_ma1xetxrwbh39vg639a9zrq8b9wk6h"); assert_eq!(MediaFileToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously().as_str(), "m_4tswec8z27wnm01njypx4vmfhgj41e"); - } - - #[test] - fn generate_for_testing_and_dev_seeding_never_use_in_production_seriously_3() { - MediaFileToken::reset_rng_for_testing_and_dev_seeding_never_use_in_production_seriously(); + // Once more... + MediaFileToken::reset_rng_for_testing_and_dev_seeding_never_use_in_production_seriously(0); assert_eq!(MediaFileToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously().as_str(), "m_q8sz47gmfw2zx02snrbz88ns9m16ab"); assert_eq!(MediaFileToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously().as_str(), "m_ma1xetxrwbh39vg639a9zrq8b9wk6h"); assert_eq!(MediaFileToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously().as_str(), "m_4tswec8z27wnm01njypx4vmfhgj41e"); diff --git a/crates/cli/dev_database_seed/src/seeding/model_weights.rs b/crates/cli/dev_database_seed/src/seeding/model_weights.rs index 8860d323c7..13e23d6014 100644 --- a/crates/cli/dev_database_seed/src/seeding/model_weights.rs +++ b/crates/cli/dev_database_seed/src/seeding/model_weights.rs @@ -132,7 +132,7 @@ pub async fn seed_weights_for_paging(mysql_pool: &Pool, user_token: UserT - Gawr Gura MOS 4 "#; - model_weight_token = ModelWeightToken(format!("{}", i)); + model_weight_token = ModelWeightToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously(); title = format!("Gawr Gura: {}", i); description = format!("Description Number {} The special edition offers significantly better quality with fewer issues. It's the model as initially envisioned.", i); description_rendered_html = rvc_markdown_description; @@ -155,7 +155,7 @@ pub async fn seed_weights_for_paging(mysql_pool: &Pool, user_token: UserT }, 21..=40 =>{ // TTS - model_weight_token = ModelWeightToken(format!("{}", i)); + model_weight_token = ModelWeightToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously(); title = format!("dragonfruitGTv1: {}", i); description = format!("Description Number {}:", i); @@ -187,7 +187,7 @@ pub async fn seed_weights_for_paging(mysql_pool: &Pool, user_token: UserT }, 41..=60 => { // SD 1.5 - model_weight_token = ModelWeightToken(format!("{}", i)); + model_weight_token = ModelWeightToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously(); title = format!("dragonfruitGTv1: {}", i); description = format!("Description Number {}:", i); @@ -232,7 +232,7 @@ pub async fn seed_weights_for_paging(mysql_pool: &Pool, user_token: UserT "#; let sdxl_image_token = "https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/be706282-2978-42a0-aaa2-73881aad94e9/width=1024/00049-2287632957-1girl,face,curly%20hair,red%20hair,white%20background,.jpeg"; - model_weight_token = ModelWeightToken(format!("{}", i)); + model_weight_token = ModelWeightToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously(); title = format!("SDXL_Niji_Special Edition: {}", i); description = format!("Description Number {}:", i); @@ -263,7 +263,7 @@ pub async fn seed_weights_for_paging(mysql_pool: &Pool, user_token: UserT "#; let lora_image_token = "https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/123645df-dee2-4239-863a-76a150b09c32/width=1024/00000-2171948503.jpeg"; - model_weight_token = ModelWeightToken(format!("{}", i)); + model_weight_token = ModelWeightToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously(); title = format!("Gawr Gura LoRA: {}", i); description = format!("Description Number {}:", i); @@ -295,7 +295,7 @@ pub async fn seed_weights_for_paging(mysql_pool: &Pool, user_token: UserT - Gawr Gura MOS 4 "#; - model_weight_token = ModelWeightToken(format!("{}", i)); + model_weight_token = ModelWeightToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously(); title = format!("Gawr Gura: {}", i); description = format!("Description Number {} The special edition offers significantly better quality with fewer issues. It's the model as initially envisioned.", i); description_rendered_html = rvc_markdown_description; @@ -356,11 +356,13 @@ pub async fn seed_weights_for_user_token( ) -> AnyhowResult<()> { info!("Seeding weights..."); - let model_weight_token1 = ModelWeightToken("11".to_string()); - let model_weight_token2 = ModelWeightToken("22".to_string()); - let model_weight_token3 = ModelWeightToken("33".to_string()); - let model_weight_token4 = ModelWeightToken("44".to_string()); - let model_weight_token5 = ModelWeightToken("55".to_string()); + ModelWeightToken::reset_rng_for_testing_and_dev_seeding_never_use_in_production_seriously(54321); + + let model_weight_token1 = ModelWeightToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously(); + let model_weight_token2 = ModelWeightToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously(); + let model_weight_token3 = ModelWeightToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously(); + let model_weight_token4 = ModelWeightToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously(); + let model_weight_token5 = ModelWeightToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously(); let model_weights_args = vec![ CreateModelWeightsArgs { @@ -503,20 +505,20 @@ pub async fn seed_weights_for_user_token( pub async fn original_seed_weights(mysql_pool: &Pool,user_token: UserToken) -> AnyhowResult<()> { - let model_weight_token1 = ModelWeightToken("1".to_string()); - let creator_token1 = UserToken("creatorToken1".to_string()); + let model_weight_token1 = ModelWeightToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously(); + let creator_token1 = UserToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously(); - let model_weight_token2 = ModelWeightToken("2".to_string()); - let creator_token2 = UserToken("creatorToken2".to_string()); + let model_weight_token2 = ModelWeightToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously(); + let creator_token2 = UserToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously(); - let model_weight_token3 = ModelWeightToken("3".to_string()); - let creator_token3 = UserToken("creatorToken3".to_string()); + let model_weight_token3 = ModelWeightToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously(); + let creator_token3 = UserToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously(); - let model_weight_token4 = ModelWeightToken("4".to_string()); - let creator_token4 = UserToken("creatorToken4".to_string()); + let model_weight_token4 = ModelWeightToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously(); + let creator_token4 = UserToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously(); - let model_weight_token5 = ModelWeightToken("5".to_string()); - let creator_token5 = UserToken("creatorToken5".to_string()); + let model_weight_token5 = ModelWeightToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously(); + let creator_token5 = UserToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously(); let model_weights_args = vec![ CreateModelWeightsArgs { diff --git a/crates/cli/dev_database_seed/src/seeding/seed_model_weights.rs b/crates/cli/dev_database_seed/src/seeding/seed_model_weights.rs index 72ab9badd3..ac6388b877 100644 --- a/crates/cli/dev_database_seed/src/seeding/seed_model_weights.rs +++ b/crates/cli/dev_database_seed/src/seeding/seed_model_weights.rs @@ -1,35 +1,31 @@ use std::path::Path; -use log::{ info, warn }; -use sqlx::{ MySql, Pool }; - -use buckets::{ public::{ media_files::bucket_file_path::MediaFileBucketPath, self }, private }; +use log::{info, warn}; +use rand::Rng; +use sqlx::{MySql, Pool}; +use buckets::public::media_files::bucket_file_path::MediaFileBucketPath; +use enums::{ + by_table::model_weights::{weights_category::WeightsCategory, weights_types::WeightsType}, + common::visibility::Visibility, +}; +use errors::AnyhowResult; use filesys::file_read_bytes::file_read_bytes; use filesys::file_size::file_size; use filesys::path_to_string::path_to_string; use hashing::sha256::sha256_hash_file::sha256_hash_file; use mimetypes::mimetype_for_bytes::get_mimetype_for_bytes; -use mimetypes::mimetype_for_file::get_mimetype_for_file; - -use storyteller_root::get_seed_tool_data_root; -use tokens::tokens::users::UserToken; -use crate::bucket_clients::BucketClients; -use crate::seeding::users::HANASHI_USER_TOKEN; - -use enums::{ - by_table::model_weights::{ weights_category::WeightsCategory, weights_types::WeightsType }, - common::visibility::Visibility, -}; - -use rand::Rng; -use errors::{ anyhow, AnyhowResult }; use mysql_queries::queries::model_weights::create_weight::{ create_weight, - CreateModelWeightsArgs, - self, + CreateModelWeightsArgs + , }; +use storyteller_root::get_seed_tool_data_root; use tokens::tokens::model_weights::ModelWeightToken; +use tokens::tokens::users::UserToken; + +use crate::bucket_clients::BucketClients; +use crate::seeding::users::HANASHI_USER_TOKEN; pub async fn seed_weights_files( mysql_pool: &Pool, @@ -37,6 +33,9 @@ pub async fn seed_weights_files( ) -> AnyhowResult<()> { info!("Seeding weights files..."); + // NB: Stable token generation. + ModelWeightToken::reset_rng_for_testing_and_dev_seeding_never_use_in_production_seriously(123); + let seeded_weights = [ ( HANASHI_USER_TOKEN, @@ -87,9 +86,8 @@ pub async fn seed_weights_files( let mut rng = rand::thread_rng(); let n: u32 = rng.gen(); - let model_weight_token = ModelWeightToken(format!("{}", n)); // random token - let model_weight_token = model_weight_token; - + let model_weight_token = ModelWeightToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously(); + let title = model_name; let description = "This is a description"; let description_rendered_html = "This is a description rendered html"; From eee75f0711b2e76a9b90fed588207f38ce9bc119 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Thu, 14 Dec 2023 04:37:44 -0500 Subject: [PATCH 039/124] polymorphic token checks (thanks kasisnu!) + new token types --- .../by_table/comments/comment_entity_type.rs | 18 ++++++++++ .../user_bookmark_entity_type.rs | 9 +++++ .../src/by_table/user_ratings/entity_type.rs | 18 ++++++++++ .../user_ratings/user_rating_entity.rs | 8 +++++ .../queries/comments/comment_entity_token.rs | 8 +++++ .../user_bookmarks/list_user_bookmarks.rs | 4 +++ .../list_user_bookmarks_result.rs | 2 ++ .../user_bookmark_entity_token.rs | 4 +++ .../comments/create_comment_handler.rs | 27 +++++++++++++++ .../create_user_bookmark_handler.rs | 34 ++++++++++++++++++- .../user_ratings/get_user_rating_handler.rs | 7 +++- .../user_ratings/set_user_rating_handler.rs | 32 +++++++++++++++-- 12 files changed, 167 insertions(+), 4 deletions(-) diff --git a/crates/_types/enums/src/by_table/comments/comment_entity_type.rs b/crates/_types/enums/src/by_table/comments/comment_entity_type.rs index 72294e2b27..014e04e17f 100644 --- a/crates/_types/enums/src/by_table/comments/comment_entity_type.rs +++ b/crates/_types/enums/src/by_table/comments/comment_entity_type.rs @@ -13,6 +13,14 @@ pub enum CommentEntityType { #[serde(rename = "user")] User, + /// Media files + #[serde(rename = "media_file")] + MediaFile, + + /// Model weights + #[serde(rename = "model_weight")] + ModelWeight, + /// TTS model (architecture does not matter) #[serde(rename = "tts_model")] TtsModel, @@ -39,6 +47,8 @@ impl CommentEntityType { pub fn to_str(&self) -> &'static str { match self { Self::User => "user", + Self::MediaFile => "media_file", + Self::ModelWeight => "model_weight", Self::TtsModel => "tts_model", Self::TtsResult => "tts_result", Self::W2lTemplate => "w2l_template", @@ -49,6 +59,8 @@ impl CommentEntityType { pub fn from_str(value: &str) -> Result { match value { "user" => Ok(Self::User), + "media_file" => Ok(Self::MediaFile), + "model_weight" => Ok(Self::ModelWeight), "tts_model" => Ok(Self::TtsModel), "tts_result" => Ok(Self::TtsResult), "w2l_template" => Ok(Self::W2lTemplate), @@ -69,6 +81,8 @@ mod tests { #[test] fn test_serialization() { assert_serialization(CommentEntityType::User, "user"); + assert_serialization(CommentEntityType::MediaFile, "media_file"); + assert_serialization(CommentEntityType::ModelWeight, "model_weight"); assert_serialization(CommentEntityType::TtsModel, "tts_model"); assert_serialization(CommentEntityType::TtsResult, "tts_result"); assert_serialization(CommentEntityType::W2lTemplate, "w2l_template"); @@ -82,6 +96,8 @@ mod tests { #[test] fn test_to_str() { assert_eq!(CommentEntityType::User.to_str(), "user"); + assert_eq!(CommentEntityType::MediaFile.to_str(), "media_file"); + assert_eq!(CommentEntityType::ModelWeight.to_str(), "model_weight"); assert_eq!(CommentEntityType::TtsModel.to_str(), "tts_model"); assert_eq!(CommentEntityType::TtsResult.to_str(), "tts_result"); assert_eq!(CommentEntityType::W2lTemplate.to_str(), "w2l_template"); @@ -91,6 +107,8 @@ mod tests { #[test] fn test_from_str() { assert_eq!(CommentEntityType::from_str("user").unwrap(), CommentEntityType::User); + assert_eq!(CommentEntityType::from_str("media_file").unwrap(), CommentEntityType::MediaFile); + assert_eq!(CommentEntityType::from_str("model_weight").unwrap(), CommentEntityType::ModelWeight); assert_eq!(CommentEntityType::from_str("tts_model").unwrap(), CommentEntityType::TtsModel); assert_eq!(CommentEntityType::from_str("tts_result").unwrap(), CommentEntityType::TtsResult); assert_eq!(CommentEntityType::from_str("w2l_template").unwrap(), CommentEntityType::W2lTemplate); diff --git a/crates/_types/enums/src/by_table/user_bookmarks/user_bookmark_entity_type.rs b/crates/_types/enums/src/by_table/user_bookmarks/user_bookmark_entity_type.rs index 69bf47cf5e..1e3fa6692c 100644 --- a/crates/_types/enums/src/by_table/user_bookmarks/user_bookmark_entity_type.rs +++ b/crates/_types/enums/src/by_table/user_bookmarks/user_bookmark_entity_type.rs @@ -33,6 +33,10 @@ pub enum UserBookmarkEntityType { #[serde(rename = "media_file")] MediaFile, + /// ModelWeight (the new way to store models) + #[serde(rename = "model_weight")] + ModelWeight, + /// VoiceConversionModel #[serde(rename = "voice_conversion_model")] VoiceConversionModel, @@ -56,6 +60,7 @@ impl UserBookmarkEntityType { Self::W2lTemplate => "w2l_template", Self::W2lResult => "w2l_result", Self::MediaFile => "media_file", + Self::ModelWeight => "model_weight", Self::VoiceConversionModel => "voice_conversion_model", Self::ZsVoice => "zs_voice", } @@ -69,6 +74,7 @@ impl UserBookmarkEntityType { "w2l_template" => Ok(Self::W2lTemplate), "w2l_result" => Ok(Self::W2lResult), "media_file" => Ok(Self::MediaFile), + "model_weight" => Ok(Self::ModelWeight), "voice_conversion_model" => Ok(Self::VoiceConversionModel), "zs_voice" => Ok(Self::ZsVoice), _ => Err(format!("invalid value: {:?}", value)), @@ -92,6 +98,7 @@ mod tests { assert_serialization(UserBookmarkEntityType::W2lTemplate, "w2l_template"); assert_serialization(UserBookmarkEntityType::W2lResult, "w2l_result"); assert_serialization(UserBookmarkEntityType::MediaFile, "media_file"); + assert_serialization(UserBookmarkEntityType::ModelWeight, "model_weight"); assert_serialization(UserBookmarkEntityType::VoiceConversionModel, "voice_conversion_model"); assert_serialization(UserBookmarkEntityType::ZsVoice, "zs_voice"); } @@ -108,6 +115,7 @@ mod tests { assert_eq!(UserBookmarkEntityType::W2lTemplate.to_str(), "w2l_template"); assert_eq!(UserBookmarkEntityType::W2lResult.to_str(), "w2l_result"); assert_eq!(UserBookmarkEntityType::MediaFile.to_str(), "media_file"); + assert_eq!(UserBookmarkEntityType::ModelWeight.to_str(), "model_weight"); assert_eq!(UserBookmarkEntityType::VoiceConversionModel.to_str(), "voice_conversion_model"); assert_eq!(UserBookmarkEntityType::ZsVoice.to_str(), "zs_voice"); } @@ -120,6 +128,7 @@ mod tests { assert_eq!(UserBookmarkEntityType::from_str("w2l_template").unwrap(), UserBookmarkEntityType::W2lTemplate); assert_eq!(UserBookmarkEntityType::from_str("w2l_result").unwrap(), UserBookmarkEntityType::W2lResult); assert_eq!(UserBookmarkEntityType::from_str("media_file").unwrap(), UserBookmarkEntityType::MediaFile); + assert_eq!(UserBookmarkEntityType::from_str("model_weight").unwrap(), UserBookmarkEntityType::ModelWeight); assert_eq!(UserBookmarkEntityType::from_str("voice_conversion_model").unwrap(), UserBookmarkEntityType::VoiceConversionModel); assert_eq!(UserBookmarkEntityType::from_str("zs_voice").unwrap(), UserBookmarkEntityType::ZsVoice); assert!(UserBookmarkEntityType::from_str("foo").is_err()); diff --git a/crates/_types/enums/src/by_table/user_ratings/entity_type.rs b/crates/_types/enums/src/by_table/user_ratings/entity_type.rs index f463471a98..025a8e4d6c 100644 --- a/crates/_types/enums/src/by_table/user_ratings/entity_type.rs +++ b/crates/_types/enums/src/by_table/user_ratings/entity_type.rs @@ -9,6 +9,14 @@ use strum::EnumIter; #[cfg_attr(test, derive(EnumIter, EnumCount))] #[derive(Clone, Copy, Eq, PartialEq, Hash, Deserialize, Serialize)] pub enum UserRatingEntityType { + /// Media files (inference results, uploads, etc.) + #[serde(rename = "media_file")] + MediaFile, + + /// Model weights (modern, polymorphic, type agnostic) + #[serde(rename = "model_weight")] + ModelWeight, + /// TTS model (architecture does not matter) #[serde(rename = "tts_model")] TtsModel, @@ -34,6 +42,8 @@ impl_mysql_enum_coders!(UserRatingEntityType); impl UserRatingEntityType { pub fn to_str(&self) -> &'static str { match self { + Self::MediaFile => "media_file", + Self::ModelWeight => "model_weight", Self::TtsModel => "tts_model", Self::TtsResult => "tts_result", Self::W2lTemplate => "w2l_template", @@ -43,6 +53,8 @@ impl UserRatingEntityType { pub fn from_str(value: &str) -> Result { match value { + "media_file" => Ok(Self::MediaFile), + "model_weight" => Ok(Self::ModelWeight), "tts_model" => Ok(Self::TtsModel), "tts_result" => Ok(Self::TtsResult), "w2l_template" => Ok(Self::W2lTemplate), @@ -62,6 +74,8 @@ mod tests { #[test] fn test_serialization() { + assert_serialization(UserRatingEntityType::MediaFile, "media_file"); + assert_serialization(UserRatingEntityType::ModelWeight, "model_weight"); assert_serialization(UserRatingEntityType::TtsModel, "tts_model"); assert_serialization(UserRatingEntityType::TtsResult, "tts_result"); assert_serialization(UserRatingEntityType::W2lTemplate, "w2l_template"); @@ -74,6 +88,8 @@ mod tests { #[test] fn test_to_str() { + assert_eq!(UserRatingEntityType::MediaFile.to_str(), "media_file"); + assert_eq!(UserRatingEntityType::ModelWeight.to_str(), "model_weight"); assert_eq!(UserRatingEntityType::TtsModel.to_str(), "tts_model"); assert_eq!(UserRatingEntityType::TtsResult.to_str(), "tts_result"); assert_eq!(UserRatingEntityType::W2lTemplate.to_str(), "w2l_template"); @@ -82,6 +98,8 @@ mod tests { #[test] fn test_from_str() { + assert_eq!(UserRatingEntityType::from_str("media_file").unwrap(), UserRatingEntityType::MediaFile); + assert_eq!(UserRatingEntityType::from_str("model_weight").unwrap(), UserRatingEntityType::ModelWeight); assert_eq!(UserRatingEntityType::from_str("tts_model").unwrap(), UserRatingEntityType::TtsModel); assert_eq!(UserRatingEntityType::from_str("tts_result").unwrap(), UserRatingEntityType::TtsResult); assert_eq!(UserRatingEntityType::from_str("w2l_template").unwrap(), UserRatingEntityType::W2lTemplate); diff --git a/crates/lib/mysql_queries/src/composite_keys/by_table/user_ratings/user_rating_entity.rs b/crates/lib/mysql_queries/src/composite_keys/by_table/user_ratings/user_rating_entity.rs index a5fe4d14b5..a100f7df30 100644 --- a/crates/lib/mysql_queries/src/composite_keys/by_table/user_ratings/user_rating_entity.rs +++ b/crates/lib/mysql_queries/src/composite_keys/by_table/user_ratings/user_rating_entity.rs @@ -1,4 +1,6 @@ use enums::by_table::user_ratings::entity_type::UserRatingEntityType; +use tokens::tokens::media_files::MediaFileToken; +use tokens::tokens::model_weights::ModelWeightToken; use tokens::tokens::tts_models::TtsModelToken; use tokens::tokens::w2l_templates::W2lTemplateToken; @@ -12,6 +14,8 @@ use tokens::tokens::w2l_templates::W2lTemplateToken; /// NB: We probably don't want to expose this type of interface to web clients because it's /// monotonous as a JSON interface. pub enum UserRatingEntity { + MediaFile(MediaFileToken), + ModelWeight(ModelWeightToken), TtsModel(TtsModelToken), W2lTemplate(W2lTemplateToken), } @@ -20,6 +24,8 @@ pub enum UserRatingEntity { impl UserRatingEntity { pub fn get_entity_type(&self) -> UserRatingEntityType { match self { + UserRatingEntity::MediaFile(_) => UserRatingEntityType::MediaFile, + UserRatingEntity::ModelWeight(_) => UserRatingEntityType::ModelWeight, UserRatingEntity::TtsModel(_) => UserRatingEntityType::TtsModel, UserRatingEntity::W2lTemplate(_) => UserRatingEntityType::W2lTemplate, } @@ -27,6 +33,8 @@ impl UserRatingEntity { pub fn get_entity_token_str(&self) -> &str { match self { + UserRatingEntity::MediaFile(token) => token.as_str(), + UserRatingEntity::ModelWeight(token) => token.as_str(), UserRatingEntity::TtsModel(token) => token.as_str(), UserRatingEntity::W2lTemplate(token) => token.as_str(), } diff --git a/crates/lib/mysql_queries/src/queries/comments/comment_entity_token.rs b/crates/lib/mysql_queries/src/queries/comments/comment_entity_token.rs index 47f9189413..885ceac73a 100644 --- a/crates/lib/mysql_queries/src/queries/comments/comment_entity_token.rs +++ b/crates/lib/mysql_queries/src/queries/comments/comment_entity_token.rs @@ -1,10 +1,14 @@ use enums::by_table::comments::comment_entity_type::CommentEntityType; +use tokens::tokens::media_files::MediaFileToken; +use tokens::tokens::model_weights::ModelWeightToken; use tokens::tokens::tts_models::TtsModelToken; use tokens::tokens::w2l_templates::W2lTemplateToken; use tokens::tokens::users::UserToken; pub enum CommentEntityToken { User(UserToken), + MediaFile(MediaFileToken), + ModelWeight(ModelWeightToken), TtsModel(TtsModelToken), TtsResult(String), // TODO: Strong type W2lTemplate(W2lTemplateToken), @@ -20,6 +24,8 @@ impl CommentEntityToken { CommentEntityType::TtsResult => Self::TtsResult(token.to_string()), CommentEntityType::W2lTemplate => Self::W2lTemplate(W2lTemplateToken::new_from_str(token)), CommentEntityType::W2lResult => Self::W2lResult(token.to_string()), + CommentEntityType::MediaFile => Self::MediaFile(MediaFileToken::new_from_str(token)), + CommentEntityType::ModelWeight => Self::ModelWeight(ModelWeightToken::new_from_str(token)), } } @@ -30,6 +36,8 @@ impl CommentEntityToken { CommentEntityToken::TtsResult(tts_result_token) => (CommentEntityType::TtsResult, tts_result_token.as_str()), CommentEntityToken::W2lTemplate(w2l_template_token) => (CommentEntityType::W2lTemplate, w2l_template_token.as_str()), CommentEntityToken::W2lResult(w2l_result_token) => (CommentEntityType::W2lResult, w2l_result_token.as_str()), + CommentEntityToken::MediaFile(media_file_token) => (CommentEntityType::MediaFile, media_file_token.as_str()), + CommentEntityToken::ModelWeight(model_weight_token) => (CommentEntityType::ModelWeight, model_weight_token.as_str()), }; (entity_type, entity_token) } diff --git a/crates/lib/mysql_queries/src/queries/user_bookmarks/list_user_bookmarks.rs b/crates/lib/mysql_queries/src/queries/user_bookmarks/list_user_bookmarks.rs index 232c7344a6..c28ab16129 100644 --- a/crates/lib/mysql_queries/src/queries/user_bookmarks/list_user_bookmarks.rs +++ b/crates/lib/mysql_queries/src/queries/user_bookmarks/list_user_bookmarks.rs @@ -33,6 +33,7 @@ SELECT media_files.media_type as `maybe_media_file_type: enums::by_table::media_files::media_file_type::MediaFileType`, media_files.origin_product_category as `maybe_media_file_origin_category: enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory`, + model_weights.title as maybe_descriptive_text_model_weight_title, tts_models.title as maybe_descriptive_text_tts_model_title, tts_results.raw_inference_text as maybe_descriptive_text_tts_result_inference_text, users.display_name as maybe_descriptive_text_user_display_name, @@ -44,6 +45,7 @@ FROM JOIN users AS u ON f.user_token = u.token +LEFT OUTER JOIN model_weights ON model_weights.token = f.entity_token LEFT OUTER JOIN media_files ON media_files.token = f.entity_token LEFT OUTER JOIN tts_models ON tts_models.token = f.entity_token LEFT OUTER JOIN tts_results ON tts_results.token = f.entity_token @@ -100,6 +102,7 @@ SELECT media_files.media_type as `maybe_media_file_type: enums::by_table::media_files::media_file_type::MediaFileType`, media_files.origin_product_category as `maybe_media_file_origin_category: enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory`, + model_weights.title as maybe_descriptive_text_model_weight_title, tts_models.title as maybe_descriptive_text_tts_model_title, tts_results.raw_inference_text as maybe_descriptive_text_tts_result_inference_text, users.display_name as maybe_descriptive_text_user_display_name, @@ -111,6 +114,7 @@ FROM JOIN users AS u ON f.user_token = u.token +LEFT OUTER JOIN model_weights ON model_weights.token = f.entity_token LEFT OUTER JOIN media_files ON media_files.token = f.entity_token LEFT OUTER JOIN tts_models ON tts_models.token = f.entity_token LEFT OUTER JOIN tts_results ON tts_results.token = f.entity_token diff --git a/crates/lib/mysql_queries/src/queries/user_bookmarks/list_user_bookmarks_result.rs b/crates/lib/mysql_queries/src/queries/user_bookmarks/list_user_bookmarks_result.rs index e56d1de9d8..f384fbcd7e 100644 --- a/crates/lib/mysql_queries/src/queries/user_bookmarks/list_user_bookmarks_result.rs +++ b/crates/lib/mysql_queries/src/queries/user_bookmarks/list_user_bookmarks_result.rs @@ -44,6 +44,7 @@ pub struct RawUserBookmarkRecord { pub (crate) maybe_media_file_type: Option, pub (crate) maybe_media_file_origin_category: Option, + pub (crate) maybe_descriptive_text_model_weight_title: Option, pub (crate) maybe_descriptive_text_tts_model_title: Option, pub (crate) maybe_descriptive_text_tts_result_inference_text: Option, pub (crate) maybe_descriptive_text_user_display_name: Option, @@ -59,6 +60,7 @@ impl RawUserBookmarkRecord { entity_token: self.entity_token, maybe_entity_descriptive_text: match self.entity_type { UserBookmarkEntityType::User => self.maybe_descriptive_text_user_display_name, + UserBookmarkEntityType::ModelWeight => self.maybe_descriptive_text_model_weight_title, UserBookmarkEntityType::TtsModel => self.maybe_descriptive_text_tts_model_title, UserBookmarkEntityType::TtsResult => self.maybe_descriptive_text_tts_result_inference_text, UserBookmarkEntityType::W2lTemplate => None, diff --git a/crates/lib/mysql_queries/src/queries/user_bookmarks/user_bookmark_entity_token.rs b/crates/lib/mysql_queries/src/queries/user_bookmarks/user_bookmark_entity_token.rs index 5fbf8224ad..aee34d7deb 100644 --- a/crates/lib/mysql_queries/src/queries/user_bookmarks/user_bookmark_entity_token.rs +++ b/crates/lib/mysql_queries/src/queries/user_bookmarks/user_bookmark_entity_token.rs @@ -1,5 +1,6 @@ use enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType; use tokens::tokens::media_files::MediaFileToken; +use tokens::tokens::model_weights::ModelWeightToken; use tokens::tokens::tts_models::TtsModelToken; use tokens::tokens::tts_results::TtsResultToken; use tokens::tokens::users::UserToken; @@ -10,6 +11,7 @@ use tokens::tokens::zs_voices::ZsVoiceToken; pub enum UserBookmarkEntityToken { User(UserToken), + ModelWeight(ModelWeightToken), TtsModel(TtsModelToken), TtsResult(TtsResultToken), W2lTemplate(W2lTemplateToken), @@ -23,6 +25,7 @@ impl UserBookmarkEntityToken { pub fn from_entity_type_and_token(entity_type: UserBookmarkEntityType, token: &str) -> Self { match entity_type { UserBookmarkEntityType::User => Self::User(UserToken::new_from_str(token)), + UserBookmarkEntityType::ModelWeight => Self::ModelWeight(ModelWeightToken::new_from_str(token)), UserBookmarkEntityType::TtsModel => Self::TtsModel(TtsModelToken::new_from_str(token)), UserBookmarkEntityType::TtsResult => Self::TtsResult(TtsResultToken::new_from_str(token)), UserBookmarkEntityType::W2lTemplate => Self::W2lTemplate(W2lTemplateToken::new_from_str(token)), @@ -36,6 +39,7 @@ impl UserBookmarkEntityToken { pub fn get_composite_keys(&self) -> (UserBookmarkEntityType, &str) { match self { UserBookmarkEntityToken::User(user_token) => (UserBookmarkEntityType::User, user_token.as_str()), + UserBookmarkEntityToken::ModelWeight(model_weight_token) => (UserBookmarkEntityType::ModelWeight, model_weight_token.as_str()), UserBookmarkEntityToken::TtsModel(tts_model_token) => (UserBookmarkEntityType::TtsModel, tts_model_token.as_str()), UserBookmarkEntityToken::TtsResult(tts_result_token) => (UserBookmarkEntityType::TtsResult, tts_result_token.as_str()), UserBookmarkEntityToken::W2lTemplate(w2l_template_token) => (UserBookmarkEntityType::W2lTemplate, w2l_template_token.as_str()), diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/comments/create_comment_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/comments/create_comment_handler.rs index 09acffdb8b..8e6f98b2ee 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/comments/create_comment_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/comments/create_comment_handler.rs @@ -16,6 +16,13 @@ use http_server_common::request::get_request_ip::get_request_ip; use mysql_queries::queries::comments::comment_entity_token::CommentEntityToken; use mysql_queries::queries::comments::insert_comment::{insert_comment, InsertCommentArgs}; use tokens::tokens::comments::CommentToken; +use tokens::tokens::media_files::MediaFileToken; +use tokens::tokens::model_weights::ModelWeightToken; +use tokens::tokens::tts_models::TtsModelToken; +use tokens::tokens::tts_results::TtsResultToken; +use tokens::tokens::users::UserToken; +use tokens::tokens::w2l_results::W2lResultToken; +use tokens::tokens::w2l_templates::W2lTemplateToken; use user_input_common::check_for_slurs::contains_slurs; use user_input_common::markdown_to_html::markdown_to_html; @@ -76,6 +83,26 @@ pub async fn create_comment_handler( server_state: web::Data>, ) -> Result { + // NB(bt,2023-12-14): Kasisnu found that we're getting entity type mismatches in production. Apart from + // querying the database for entity existence, this is the next best way to prevent incorrect comment + // attachment. This is a bit of a bad process, though, since the token types are supposed to be opaque. + let token = request.entity_token.as_str(); + let token_prefix_matches = match request.entity_type { + // NB: Users had an older prefix (U:) that got replaced with the new prefix (user_) + CommentEntityType::User => token.starts_with(UserToken::token_prefix()) || token.starts_with("U:"), + CommentEntityType::MediaFile => token.starts_with(MediaFileToken::token_prefix()), + CommentEntityType::ModelWeight => token.starts_with(ModelWeightToken::token_prefix()), + CommentEntityType::TtsModel => token.starts_with(TtsModelToken::token_prefix()), + CommentEntityType::TtsResult => token.starts_with(TtsResultToken::token_prefix()), + CommentEntityType::W2lTemplate => token.starts_with(W2lTemplateToken::token_prefix()), + CommentEntityType::W2lResult => token.starts_with(W2lResultToken::token_prefix()), + }; + + if !token_prefix_matches { + warn!("invalid token prefix: {:?} for {:?}", request.entity_token, request.entity_type); + return Err(CreateCommentError::BadInput("invalid token prefix".to_string())); + } + let mut mysql_connection = server_state.mysql_pool .acquire() .await diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/create_user_bookmark_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/create_user_bookmark_handler.rs index b62fe2feeb..43f0fe6ac1 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/create_user_bookmark_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/create_user_bookmark_handler.rs @@ -12,9 +12,19 @@ use actix_web::http::StatusCode; use log::warn; use enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType; -use mysql_queries::queries::user_bookmarks::user_bookmark_entity_token::UserBookmarkEntityToken; use mysql_queries::queries::user_bookmarks::create_user_bookmark::{create_user_bookmark, CreateUserBookmarkArgs}; +use mysql_queries::queries::user_bookmarks::user_bookmark_entity_token::UserBookmarkEntityToken; +use tokens::tokens::media_files::MediaFileToken; +use tokens::tokens::model_weights::ModelWeightToken; +use tokens::tokens::tts_models::TtsModelToken; +use tokens::tokens::tts_results::TtsResultToken; use tokens::tokens::user_bookmarks::UserBookmarkToken; +use tokens::tokens::users::UserToken; +use tokens::tokens::voice_conversion_models::VoiceConversionModelToken; +use tokens::tokens::w2l_results::W2lResultToken; +use tokens::tokens::w2l_templates::W2lTemplateToken; +use tokens::tokens::zs_voices::ZsVoiceToken; + use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; use crate::server_state::ServerState; @@ -70,6 +80,28 @@ pub async fn create_user_bookmark_handler( server_state: web::Data>, ) -> Result { + // NB(bt,2023-12-14): Kasisnu found that we're getting entity type mismatches in production. Apart from + // querying the database for entity existence, this is the next best way to prevent incorrect comment + // attachment. This is a bit of a bad process, though, since the token types are supposed to be opaque. + let token = request.entity_token.as_str(); + let token_prefix_matches = match request.entity_type { + // NB: Users had an older prefix (U:) that got replaced with the new prefix (user_) + UserBookmarkEntityType::User => token.starts_with(UserToken::token_prefix()) || token.starts_with("U:"), + UserBookmarkEntityType::MediaFile => token.starts_with(MediaFileToken::token_prefix()), + UserBookmarkEntityType::ModelWeight => token.starts_with(ModelWeightToken::token_prefix()), + UserBookmarkEntityType::TtsModel => token.starts_with(TtsModelToken::token_prefix()), + UserBookmarkEntityType::TtsResult => token.starts_with(TtsResultToken::token_prefix()), + UserBookmarkEntityType::W2lTemplate => token.starts_with(W2lTemplateToken::token_prefix()), + UserBookmarkEntityType::W2lResult => token.starts_with(W2lResultToken::token_prefix()), + UserBookmarkEntityType::VoiceConversionModel => token.starts_with(VoiceConversionModelToken::token_prefix()), + UserBookmarkEntityType::ZsVoice => token.starts_with(ZsVoiceToken::token_prefix()), + }; + + if !token_prefix_matches { + warn!("invalid token prefix: {:?} for {:?}", request.entity_token, request.entity_type); + return Err(CreateUserBookmarkError::BadInput("invalid token prefix".to_string())); + } + let mut mysql_connection = server_state.mysql_pool .acquire() .await diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/user_ratings/get_user_rating_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/user_ratings/get_user_rating_handler.rs index 228b053afa..5c7f077910 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/user_ratings/get_user_rating_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/user_ratings/get_user_rating_handler.rs @@ -9,6 +9,8 @@ use enums::by_table::user_ratings::rating_value::UserRatingValue; use http_server_common::response::serialize_as_json_error::serialize_as_json_error; use mysql_queries::composite_keys::by_table::user_ratings::user_rating_entity::UserRatingEntity; use mysql_queries::queries::users::user_ratings::get_user_rating::{Args, get_user_rating}; +use tokens::tokens::media_files::MediaFileToken; +use tokens::tokens::model_weights::ModelWeightToken; use tokens::tokens::tts_models::TtsModelToken; use tokens::tokens::w2l_templates::W2lTemplateToken; @@ -105,9 +107,12 @@ pub async fn get_user_rating_handler( UserRatingEntityType::W2lTemplate => UserRatingEntity::W2lTemplate( W2lTemplateToken::new_from_str(&path.entity_token)), + UserRatingEntityType::MediaFile => UserRatingEntity::MediaFile(MediaFileToken::new_from_str(&path.entity_token)), + UserRatingEntityType::ModelWeight => UserRatingEntity::ModelWeight(ModelWeightToken::new_from_str(&path.entity_token)), + // TODO: We'll handle ratings of more types in the future. UserRatingEntityType::W2lResult | UserRatingEntityType::TtsResult => - return Err(GetUserRatingError::BadInput("type not yet supported".to_string())) + return Err(GetUserRatingError::BadInput("type not yet supported".to_string())), }; let maybe_rating = get_user_rating(Args { diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/user_ratings/set_user_rating_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/user_ratings/set_user_rating_handler.rs index 8d5af40699..e25a3d6e85 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/user_ratings/set_user_rating_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/user_ratings/set_user_rating_handler.rs @@ -2,7 +2,7 @@ use std::sync::Arc; use actix_web::{HttpRequest, HttpResponse, ResponseError, web}; use actix_web::http::StatusCode; -use log::{error, info}; +use log::{error, info, warn}; use enums::by_table::user_ratings::entity_type::UserRatingEntityType; use enums::by_table::user_ratings::rating_value::UserRatingValue; @@ -11,7 +11,11 @@ use http_server_common::response::serialize_as_json_error::serialize_as_json_err use mysql_queries::composite_keys::by_table::user_ratings::user_rating_entity::UserRatingEntity; use mysql_queries::queries::users::user_ratings::update_tts_model_ratings::update_tts_model_ratings; use mysql_queries::queries::users::user_ratings::upsert_user_rating::{Args, upsert_user_rating}; +use tokens::tokens::media_files::MediaFileToken; +use tokens::tokens::model_weights::ModelWeightToken; use tokens::tokens::tts_models::TtsModelToken; +use tokens::tokens::tts_results::TtsResultToken; +use tokens::tokens::w2l_results::W2lResultToken; use tokens::tokens::w2l_templates::W2lTemplateToken; use crate::server_state::ServerState; @@ -73,6 +77,27 @@ pub async fn set_user_rating_handler( request: web::Json, server_state: web::Data>) -> Result { + // NB(bt,2023-12-14): Kasisnu found that we're getting entity type mismatches in production. Apart from + // querying the database for entity existence, this is the next best way to prevent incorrect comment + // attachment. This is a bit of a bad process, though, since the token types are supposed to be opaque. + let token = request.entity_token.as_str(); + let token_prefix_matches = match request.entity_type { + // NB: Users had an older prefix (U:) that got replaced with the new prefix (user_) + UserRatingEntityType::MediaFile => token.starts_with(MediaFileToken::token_prefix()), + UserRatingEntityType::ModelWeight => token.starts_with(ModelWeightToken::token_prefix()), + UserRatingEntityType::TtsModel => token.starts_with(TtsModelToken::token_prefix()), + UserRatingEntityType::TtsResult => token.starts_with(TtsResultToken::token_prefix()), + UserRatingEntityType::W2lTemplate => token.starts_with(W2lTemplateToken::token_prefix()), + UserRatingEntityType::W2lResult => token.starts_with(W2lResultToken::token_prefix()), + //UserRatingEntityType::VoiceConversionModel => token.starts_with(VoiceConversionModelToken::token_prefix()), + //UserRatingEntityType::ZsVoice => token.starts_with(ZsVoiceToken::token_prefix()), + }; + + if !token_prefix_matches { + warn!("invalid token prefix: {:?} for {:?}", request.entity_token, request.entity_type); + return Err(SetUserRatingError::BadInput("invalid token prefix".to_string())); + } + let mut mysql_connection = server_state.mysql_pool.acquire() .await .map_err(|e| { @@ -100,6 +125,9 @@ pub async fn set_user_rating_handler( let ip_address = get_request_ip(&http_request); let entity= match request.entity_type { + UserRatingEntityType::MediaFile => UserRatingEntity::MediaFile(MediaFileToken::new_from_str(&request.entity_token)), + UserRatingEntityType::ModelWeight => UserRatingEntity::ModelWeight(ModelWeightToken::new_from_str(&request.entity_token)), + UserRatingEntityType::TtsModel => UserRatingEntity::TtsModel( TtsModelToken::new_from_str(&request.entity_token)), @@ -108,7 +136,7 @@ pub async fn set_user_rating_handler( // TODO: We'll handle ratings of more types in the future. UserRatingEntityType::W2lResult | UserRatingEntityType::TtsResult => - return Err(SetUserRatingError::BadInput("type not yet supported".to_string())) + return Err(SetUserRatingError::BadInput("type not yet supported".to_string())), }; let _r = upsert_user_rating(Args { From ff7ea2a4dbb3176ac3683d367a3e5e5ffcc4d335 Mon Sep 17 00:00:00 2001 From: kasisnu <5044120+kasisnu@users.noreply.github.com> Date: Thu, 14 Dec 2023 16:25:51 +0530 Subject: [PATCH 040/124] make media endpoint for profiles follow public pagination --- ...b1efd0cfa6b20899151f9e7f1a122c1f7a70e.json | 201 ------------------ ...9449362c074fc2397e23ecd175b6a0425b16b.json | 201 ------------------ .../media_files/list_media_files_for_user.rs | 131 +++++++----- .../common_responses/pagination_page.rs | 4 +- .../media_files/list_media_files_for_user.rs | 53 ++--- 5 files changed, 96 insertions(+), 494 deletions(-) delete mode 100644 .sqlx/query-d9c00b3c78ed6ec31b281c7ea5fb1efd0cfa6b20899151f9e7f1a122c1f7a70e.json delete mode 100644 .sqlx/query-eea9531d5261833b93baadee8b99449362c074fc2397e23ecd175b6a0425b16b.json diff --git a/.sqlx/query-d9c00b3c78ed6ec31b281c7ea5fb1efd0cfa6b20899151f9e7f1a122c1f7a70e.json b/.sqlx/query-d9c00b3c78ed6ec31b281c7ea5fb1efd0cfa6b20899151f9e7f1a122c1f7a70e.json deleted file mode 100644 index 33334d1769..0000000000 --- a/.sqlx/query-d9c00b3c78ed6ec31b281c7ea5fb1efd0cfa6b20899151f9e7f1a122c1f7a70e.json +++ /dev/null @@ -1,201 +0,0 @@ -{ - "db_name": "MySQL", - "query": "\nSELECT\n f.token as `token: tokens::tokens::user_bookmarks::UserBookmarkToken`,\n f.entity_type as `entity_type: enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType`,\n f.entity_token,\n f.user_token as `user_token: tokens::tokens::users::UserToken`,\n u.username,\n u.display_name as user_display_name,\n u.email_gravatar_hash as user_gravatar_hash,\n f.created_at,\n f.updated_at,\n f.deleted_at,\n\n media_files.media_type as `maybe_media_file_type: enums::by_table::media_files::media_file_type::MediaFileType`,\n media_files.origin_product_category as `maybe_media_file_origin_category: enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory`,\n\n tts_models.title as maybe_descriptive_text_tts_model_title,\n tts_results.raw_inference_text as maybe_descriptive_text_tts_result_inference_text,\n users.display_name as maybe_descriptive_text_user_display_name,\n voice_conversion_models.title as maybe_descriptive_text_voice_conversion_model_title,\n zs_voices.title as maybe_descriptive_text_zs_voice_title\n\nFROM\n user_bookmarks AS f\nJOIN users AS u\n ON f.user_token = u.token\n\nLEFT OUTER JOIN media_files ON media_files.token = f.entity_token\nLEFT OUTER JOIN tts_models ON tts_models.token = f.entity_token\nLEFT OUTER JOIN tts_results ON tts_results.token = f.entity_token\nLEFT OUTER JOIN users ON users.token = f.entity_token\nLEFT OUTER JOIN voice_conversion_models ON voice_conversion_models.token = f.entity_token\nLEFT OUTER JOIN zs_voices ON zs_voices.token = f.entity_token\n\nWHERE\n u.username = ?\n AND f.entity_type = ?\n AND f.deleted_at IS NULL\nORDER BY f.id DESC\nLIMIT 50\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "token: tokens::tokens::user_bookmarks::UserBookmarkToken", - "type_info": { - "type": "VarString", - "flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE", - "char_set": 224, - "max_size": 128 - } - }, - { - "ordinal": 1, - "name": "entity_type: enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType", - "type_info": { - "type": "VarString", - "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE", - "char_set": 224, - "max_size": 128 - } - }, - { - "ordinal": 2, - "name": "entity_token", - "type_info": { - "type": "VarString", - "flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE", - "char_set": 224, - "max_size": 128 - } - }, - { - "ordinal": 3, - "name": "user_token: tokens::tokens::users::UserToken", - "type_info": { - "type": "VarString", - "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE", - "char_set": 224, - "max_size": 128 - } - }, - { - "ordinal": 4, - "name": "username", - "type_info": { - "type": "VarString", - "flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE", - "char_set": 224, - "max_size": 80 - } - }, - { - "ordinal": 5, - "name": "user_display_name", - "type_info": { - "type": "VarString", - "flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE", - "char_set": 224, - "max_size": 80 - } - }, - { - "ordinal": 6, - "name": "user_gravatar_hash", - "type_info": { - "type": "String", - "flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE", - "char_set": 224, - "max_size": 128 - } - }, - { - "ordinal": 7, - "name": "created_at", - "type_info": { - "type": "Timestamp", - "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | TIMESTAMP", - "char_set": 63, - "max_size": 19 - } - }, - { - "ordinal": 8, - "name": "updated_at", - "type_info": { - "type": "Timestamp", - "flags": "NOT_NULL | BINARY | TIMESTAMP | ON_UPDATE_NOW", - "char_set": 63, - "max_size": 19 - } - }, - { - "ordinal": 9, - "name": "deleted_at", - "type_info": { - "type": "Timestamp", - "flags": "MULTIPLE_KEY | BINARY", - "char_set": 63, - "max_size": 19 - } - }, - { - "ordinal": 10, - "name": "maybe_media_file_type: enums::by_table::media_files::media_file_type::MediaFileType", - "type_info": { - "type": "VarString", - "flags": "MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE", - "char_set": 224, - "max_size": 64 - } - }, - { - "ordinal": 11, - "name": "maybe_media_file_origin_category: enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory", - "type_info": { - "type": "VarString", - "flags": "MULTIPLE_KEY | BINARY", - "char_set": 224, - "max_size": 64 - } - }, - { - "ordinal": 12, - "name": "maybe_descriptive_text_tts_model_title", - "type_info": { - "type": "VarString", - "flags": "BINARY | NO_DEFAULT_VALUE", - "char_set": 224, - "max_size": 1020 - } - }, - { - "ordinal": 13, - "name": "maybe_descriptive_text_tts_result_inference_text", - "type_info": { - "type": "Blob", - "flags": "BLOB | BINARY | NO_DEFAULT_VALUE", - "char_set": 224, - "max_size": 262140 - } - }, - { - "ordinal": 14, - "name": "maybe_descriptive_text_user_display_name", - "type_info": { - "type": "VarString", - "flags": "BINARY | NO_DEFAULT_VALUE", - "char_set": 224, - "max_size": 80 - } - }, - { - "ordinal": 15, - "name": "maybe_descriptive_text_voice_conversion_model_title", - "type_info": { - "type": "VarString", - "flags": "BINARY | NO_DEFAULT_VALUE", - "char_set": 224, - "max_size": 1020 - } - }, - { - "ordinal": 16, - "name": "maybe_descriptive_text_zs_voice_title", - "type_info": { - "type": "VarString", - "flags": "BINARY | NO_DEFAULT_VALUE", - "char_set": 224, - "max_size": 1020 - } - } - ], - "parameters": { - "Right": 2 - }, - "nullable": [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true - ] - }, - "hash": "d9c00b3c78ed6ec31b281c7ea5fb1efd0cfa6b20899151f9e7f1a122c1f7a70e" -} diff --git a/.sqlx/query-eea9531d5261833b93baadee8b99449362c074fc2397e23ecd175b6a0425b16b.json b/.sqlx/query-eea9531d5261833b93baadee8b99449362c074fc2397e23ecd175b6a0425b16b.json deleted file mode 100644 index 55d497beee..0000000000 --- a/.sqlx/query-eea9531d5261833b93baadee8b99449362c074fc2397e23ecd175b6a0425b16b.json +++ /dev/null @@ -1,201 +0,0 @@ -{ - "db_name": "MySQL", - "query": "\nSELECT\n f.token as `token: tokens::tokens::user_bookmarks::UserBookmarkToken`,\n f.entity_type as `entity_type: enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType`,\n f.entity_token,\n f.user_token as `user_token: tokens::tokens::users::UserToken`,\n u.username,\n u.display_name as user_display_name,\n u.email_gravatar_hash as user_gravatar_hash,\n f.created_at,\n f.updated_at,\n f.deleted_at,\n\n media_files.media_type as `maybe_media_file_type: enums::by_table::media_files::media_file_type::MediaFileType`,\n media_files.origin_product_category as `maybe_media_file_origin_category: enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory`,\n\n tts_models.title as maybe_descriptive_text_tts_model_title,\n tts_results.raw_inference_text as maybe_descriptive_text_tts_result_inference_text,\n users.display_name as maybe_descriptive_text_user_display_name,\n voice_conversion_models.title as maybe_descriptive_text_voice_conversion_model_title,\n zs_voices.title as maybe_descriptive_text_zs_voice_title\n\nFROM\n user_bookmarks AS f\nJOIN users AS u\n ON f.user_token = u.token\n\nLEFT OUTER JOIN media_files ON media_files.token = f.entity_token\nLEFT OUTER JOIN tts_models ON tts_models.token = f.entity_token\nLEFT OUTER JOIN tts_results ON tts_results.token = f.entity_token\nLEFT OUTER JOIN users ON users.token = f.entity_token\nLEFT OUTER JOIN voice_conversion_models ON voice_conversion_models.token = f.entity_token\nLEFT OUTER JOIN zs_voices ON zs_voices.token = f.entity_token\n\nWHERE\n u.username = ?\n AND f.deleted_at IS NULL\nORDER BY f.id DESC\nLIMIT 50\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "token: tokens::tokens::user_bookmarks::UserBookmarkToken", - "type_info": { - "type": "VarString", - "flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE", - "char_set": 224, - "max_size": 128 - } - }, - { - "ordinal": 1, - "name": "entity_type: enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType", - "type_info": { - "type": "VarString", - "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE", - "char_set": 224, - "max_size": 128 - } - }, - { - "ordinal": 2, - "name": "entity_token", - "type_info": { - "type": "VarString", - "flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE", - "char_set": 224, - "max_size": 128 - } - }, - { - "ordinal": 3, - "name": "user_token: tokens::tokens::users::UserToken", - "type_info": { - "type": "VarString", - "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE", - "char_set": 224, - "max_size": 128 - } - }, - { - "ordinal": 4, - "name": "username", - "type_info": { - "type": "VarString", - "flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE", - "char_set": 224, - "max_size": 80 - } - }, - { - "ordinal": 5, - "name": "user_display_name", - "type_info": { - "type": "VarString", - "flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE", - "char_set": 224, - "max_size": 80 - } - }, - { - "ordinal": 6, - "name": "user_gravatar_hash", - "type_info": { - "type": "String", - "flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE", - "char_set": 224, - "max_size": 128 - } - }, - { - "ordinal": 7, - "name": "created_at", - "type_info": { - "type": "Timestamp", - "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | TIMESTAMP", - "char_set": 63, - "max_size": 19 - } - }, - { - "ordinal": 8, - "name": "updated_at", - "type_info": { - "type": "Timestamp", - "flags": "NOT_NULL | BINARY | TIMESTAMP | ON_UPDATE_NOW", - "char_set": 63, - "max_size": 19 - } - }, - { - "ordinal": 9, - "name": "deleted_at", - "type_info": { - "type": "Timestamp", - "flags": "MULTIPLE_KEY | BINARY", - "char_set": 63, - "max_size": 19 - } - }, - { - "ordinal": 10, - "name": "maybe_media_file_type: enums::by_table::media_files::media_file_type::MediaFileType", - "type_info": { - "type": "VarString", - "flags": "MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE", - "char_set": 224, - "max_size": 64 - } - }, - { - "ordinal": 11, - "name": "maybe_media_file_origin_category: enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory", - "type_info": { - "type": "VarString", - "flags": "MULTIPLE_KEY | BINARY", - "char_set": 224, - "max_size": 64 - } - }, - { - "ordinal": 12, - "name": "maybe_descriptive_text_tts_model_title", - "type_info": { - "type": "VarString", - "flags": "BINARY | NO_DEFAULT_VALUE", - "char_set": 224, - "max_size": 1020 - } - }, - { - "ordinal": 13, - "name": "maybe_descriptive_text_tts_result_inference_text", - "type_info": { - "type": "Blob", - "flags": "BLOB | BINARY | NO_DEFAULT_VALUE", - "char_set": 224, - "max_size": 262140 - } - }, - { - "ordinal": 14, - "name": "maybe_descriptive_text_user_display_name", - "type_info": { - "type": "VarString", - "flags": "BINARY | NO_DEFAULT_VALUE", - "char_set": 224, - "max_size": 80 - } - }, - { - "ordinal": 15, - "name": "maybe_descriptive_text_voice_conversion_model_title", - "type_info": { - "type": "VarString", - "flags": "BINARY | NO_DEFAULT_VALUE", - "char_set": 224, - "max_size": 1020 - } - }, - { - "ordinal": 16, - "name": "maybe_descriptive_text_zs_voice_title", - "type_info": { - "type": "VarString", - "flags": "BINARY | NO_DEFAULT_VALUE", - "char_set": 224, - "max_size": 1020 - } - } - ], - "parameters": { - "Right": 1 - }, - "nullable": [ - false, - false, - false, - false, - false, - false, - false, - false, - false, - true, - true, - true, - true, - true, - true, - true, - true - ] - }, - "hash": "eea9531d5261833b93baadee8b99449362c074fc2397e23ecd175b6a0425b16b" -} diff --git a/crates/lib/mysql_queries/src/queries/media_files/list_media_files_for_user.rs b/crates/lib/mysql_queries/src/queries/media_files/list_media_files_for_user.rs index 87bcc96ee8..d7115cd5a6 100644 --- a/crates/lib/mysql_queries/src/queries/media_files/list_media_files_for_user.rs +++ b/crates/lib/mysql_queries/src/queries/media_files/list_media_files_for_user.rs @@ -1,4 +1,5 @@ use chrono::{DateTime, Utc}; +use log::warn; use sqlx::{FromRow, MySql, MySqlPool, QueryBuilder, Row}; use sqlx::mysql::MySqlRow; @@ -11,16 +12,15 @@ use enums::traits::mysql_from_row::MySqlFromRow; use errors::AnyhowResult; use tokens::tokens::media_files::MediaFileToken; + + pub struct MediaFileListPage { pub records: Vec, pub sort_ascending: bool, - /// ID of the first record. - pub first_id: Option, - - /// ID of the last record. - pub last_id: Option, + pub current_page: usize, + pub total_page_count: usize, } pub struct MediaFileListItem { @@ -51,9 +51,9 @@ pub enum ViewAs { pub struct ListMediaFileForUserArgs<'a> { pub username: &'a str, - pub limit: usize, pub maybe_filter_media_type: Option, - pub maybe_offset: Option, + pub page_size: usize, + pub page_index: usize, pub cursor_is_reversed: bool, pub view_as: ViewAs, pub mysql_pool: &'a MySqlPool, @@ -61,25 +61,42 @@ pub struct ListMediaFileForUserArgs<'a> { pub async fn list_media_files_for_user(args: ListMediaFileForUserArgs<'_>) -> AnyhowResult { + /// Let's figure out how many results we could have returned total + let count_fields = select_total_count_field(); + let mut count_query_builder = query_builder( + args.maybe_filter_media_type, + args.username, + false, + 0, + 0, + args.cursor_is_reversed, + args.view_as, + count_fields.as_str(), + ); + + let row_count_query = count_query_builder.build_query_scalar::(); + let row_count_result = row_count_query.fetch_one(args.mysql_pool).await?; + /// Figure out limit start and end based on page size and indexes as requested + let limit_start = args.page_size * args.page_index; + let limit_end = limit_start + args.page_size; + + /// Now fetch the actual results with all the fields + let result_fields = select_result_fields(); let mut query = query_builder( args.maybe_filter_media_type, args.username, - args.limit, - args.maybe_offset, + true, + limit_start, + limit_end, args.cursor_is_reversed, args.view_as, + result_fields.as_str(), ); let query = query.build_query_as::(); - let results = query.fetch_all(args.mysql_pool).await?; - let first_id = results.first() - .map(|raw_result| raw_result.id); - - let last_id = results.last() - .map(|raw_result| raw_result.id); - + let number_of_pages = (row_count_result / args.page_size as i64) as usize; let results = results.into_iter() .map(|record| { MediaFileListItem { @@ -102,43 +119,59 @@ pub async fn list_media_files_for_user(args: ListMediaFileForUserArgs<'_>) -> An Ok(MediaFileListPage { records: results, sort_ascending: !args.cursor_is_reversed, - first_id, - last_id, + current_page: args.page_index, + total_page_count: number_of_pages, }) } + +fn select_result_fields() -> String { + r#" + m.id, + m.token, + + m.origin_category, + m.origin_product_category, + + m.maybe_origin_model_type, + m.maybe_origin_model_token, + + m.media_type, + + m.public_bucket_directory_hash, + m.maybe_public_bucket_prefix, + m.maybe_public_bucket_extension, + + m.creator_set_visibility, + m.created_at, + m.updated_at + "# + .to_string() +} + +fn select_total_count_field() -> String { + r#" + COUNT(m.id) AS total_count + "# + .to_string() +} + fn query_builder<'a>( maybe_filter_media_type: Option, username: &'a str, - limit: usize, - maybe_offset: Option, + enforce_limits: bool, + limit_start: usize, + limit_end: usize, cursor_is_reversed: bool, view_as: ViewAs, + select_fields: &'a str, ) -> QueryBuilder<'a, MySql> { // NB: Query cannot be statically checked by sqlx let mut query_builder: QueryBuilder = QueryBuilder::new( - r#" + format!(r#" SELECT - m.id, - m.token, - - m.origin_category, - m.origin_product_category, - - m.maybe_origin_model_type, - m.maybe_origin_model_token, - - m.media_type, - - m.public_bucket_directory_hash, - m.maybe_public_bucket_prefix, - m.maybe_public_bucket_extension, - - m.creator_set_visibility, - m.created_at, - m.updated_at - + {select_fields} FROM media_files AS m LEFT OUTER JOIN users AS u ON m.maybe_creator_user_token = u.token @@ -146,7 +179,7 @@ LEFT OUTER JOIN users AS u WHERE m.user_deleted_at IS NULL AND m.mod_deleted_at IS NULL "# - ); + )); query_builder.push(" AND u.username = "); query_builder.push_bind(username); @@ -171,21 +204,19 @@ WHERE m.user_deleted_at IS NULL } } - if let Some(offset) = maybe_offset { - if cursor_is_reversed { - query_builder.push(format!(" AND m.id < {offset} ")); - } else { - query_builder.push(format!(" AND m.id > {offset} ")); - } - } - if cursor_is_reversed { query_builder.push(" ORDER BY m.id ASC "); } else { query_builder.push(" ORDER BY m.id DESC "); } - query_builder.push(format!(" LIMIT {limit} ")); + if (enforce_limits) { + if cursor_is_reversed { + query_builder.push(format!(" LIMIT {limit_start}, {limit_end} ")); + } else { + query_builder.push(format!(" LIMIT {limit_end}, {limit_start} ")); + } + } query_builder } diff --git a/crates/service/web/storyteller_web/src/http_server/common_responses/pagination_page.rs b/crates/service/web/storyteller_web/src/http_server/common_responses/pagination_page.rs index 3e64af9626..50534944ef 100644 --- a/crates/service/web/storyteller_web/src/http_server/common_responses/pagination_page.rs +++ b/crates/service/web/storyteller_web/src/http_server/common_responses/pagination_page.rs @@ -8,10 +8,10 @@ #[derive(Serialize)] pub struct PaginationPage { /// The current page number - pub current: u64, + pub current: usize, /// How many pages there are in total - pub total_page_count: u64, + pub total_page_count: usize, } #[cfg(test)] diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files_for_user.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files_for_user.rs index bd3eda2b78..ef03b3dd48 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files_for_user.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files_for_user.rs @@ -16,6 +16,7 @@ use mysql_queries::queries::media_files::list_media_files_for_user::{list_media_ use tokens::tokens::media_files::MediaFileToken; use crate::http_server::common_responses::pagination_cursors::PaginationCursors; +use crate::http_server::common_responses::pagination_page::PaginationPage; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; use crate::server_state::ServerState; @@ -27,7 +28,8 @@ pub struct PathInfo { #[derive(Deserialize)] pub struct QueryParams { pub sort_ascending: Option, - pub limit: Option, + pub page_size: Option, + pub page_index: Option, pub cursor: Option, pub cursor_is_reversed: Option, pub filter_media_type: Option, @@ -37,7 +39,7 @@ pub struct QueryParams { pub struct SuccessResponse { pub success: bool, pub results: Vec, - pub pagination: PaginationCursors, + pub pagination: PaginationPage, } #[derive(Serialize)] @@ -115,21 +117,13 @@ pub async fn list_media_files_for_user_handler( }; // TODO(bt,2023-12-04): Enforce real maximums and defaults - let limit = query.limit.unwrap_or(25); + let limit = query.page_size.unwrap_or(25); let sort_ascending = query.sort_ascending.unwrap_or(false); let cursor_is_reversed = query.cursor_is_reversed.unwrap_or(false); - let cursor = if let Some(cursor) = query.cursor.as_deref() { - let cursor = server_state.sort_key_crypto.decrypt_id(cursor) - .map_err(|e| { - warn!("crypto error: {:?}", e); - ErrorResponse::ServerError - })?; - Some(cursor as usize) - } else { - None - }; + let page_size = query.page_size.unwrap_or_else(|| 25); + let page_index = query.page_index.unwrap_or_else(|| 0); let view_as = if is_author { ViewAs::Author @@ -139,11 +133,12 @@ pub async fn list_media_files_for_user_handler( ViewAs::AnotherUser }; + let query_results = list_media_files_for_user(ListMediaFileForUserArgs { username: &path.username, - limit, maybe_filter_media_type: query.filter_media_type, - maybe_offset: cursor, + page_size, + page_index, cursor_is_reversed, view_as, mysql_pool: &server_state.mysql_pool, @@ -158,27 +153,6 @@ pub async fn list_media_files_for_user_handler( } }; - let cursor_next = if let Some(id) = results_page.last_id { - let cursor = server_state.sort_key_crypto.encrypt_id(id as u64) - .map_err(|e| { - warn!("crypto error: {:?}", e); - ErrorResponse::ServerError - })?; - Some(cursor) - } else { - None - }; - - let cursor_previous = if let Some(id) = results_page.first_id { - let cursor = server_state.sort_key_crypto.encrypt_id(id as u64) - .map_err(|e| { - warn!("crypto error: {:?}", e); - ErrorResponse::ServerError - })?; - Some(cursor) - } else { - None - }; let results = results_page.records.into_iter() .map(|record| MediaFileListItem { @@ -200,10 +174,9 @@ pub async fn list_media_files_for_user_handler( let response = SuccessResponse { success: true, results, - pagination: PaginationCursors { - maybe_next: cursor_next, - maybe_previous: cursor_previous, - cursor_is_reversed, + pagination: PaginationPage{ + current: results_page.current_page, + total_page_count: results_page.total_page_count, } }; From 8618e774e7bfa7af95f531eb1d737f94c0140646 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Thu, 14 Dec 2023 13:37:25 -0500 Subject: [PATCH 041/124] codegen db --- ...663d0eb3d969365f6b2fd048ca41c5c455b2.json} | 23 +- ...44666e6c7c0f24b5da79dde828ffdb2c8302.json} | 23 +- .../media_files/list_media_files_by_tokens.rs | 264 ++++++++++++++++++ 3 files changed, 298 insertions(+), 12 deletions(-) rename .sqlx/{query-d9c00b3c78ed6ec31b281c7ea5fb1efd0cfa6b20899151f9e7f1a122c1f7a70e.json => query-3a7ac7f979ac270dad1070031d0d663d0eb3d969365f6b2fd048ca41c5c455b2.json} (78%) rename .sqlx/{query-eea9531d5261833b93baadee8b99449362c074fc2397e23ecd175b6a0425b16b.json => query-707af35ee4ab4519f28e6d69982944666e6c7c0f24b5da79dde828ffdb2c8302.json} (79%) create mode 100644 crates/lib/mysql_queries/src/queries/media_files/list_media_files_by_tokens.rs diff --git a/.sqlx/query-d9c00b3c78ed6ec31b281c7ea5fb1efd0cfa6b20899151f9e7f1a122c1f7a70e.json b/.sqlx/query-3a7ac7f979ac270dad1070031d0d663d0eb3d969365f6b2fd048ca41c5c455b2.json similarity index 78% rename from .sqlx/query-d9c00b3c78ed6ec31b281c7ea5fb1efd0cfa6b20899151f9e7f1a122c1f7a70e.json rename to .sqlx/query-3a7ac7f979ac270dad1070031d0d663d0eb3d969365f6b2fd048ca41c5c455b2.json index 33334d1769..921e62dbe0 100644 --- a/.sqlx/query-d9c00b3c78ed6ec31b281c7ea5fb1efd0cfa6b20899151f9e7f1a122c1f7a70e.json +++ b/.sqlx/query-3a7ac7f979ac270dad1070031d0d663d0eb3d969365f6b2fd048ca41c5c455b2.json @@ -1,6 +1,6 @@ { "db_name": "MySQL", - "query": "\nSELECT\n f.token as `token: tokens::tokens::user_bookmarks::UserBookmarkToken`,\n f.entity_type as `entity_type: enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType`,\n f.entity_token,\n f.user_token as `user_token: tokens::tokens::users::UserToken`,\n u.username,\n u.display_name as user_display_name,\n u.email_gravatar_hash as user_gravatar_hash,\n f.created_at,\n f.updated_at,\n f.deleted_at,\n\n media_files.media_type as `maybe_media_file_type: enums::by_table::media_files::media_file_type::MediaFileType`,\n media_files.origin_product_category as `maybe_media_file_origin_category: enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory`,\n\n tts_models.title as maybe_descriptive_text_tts_model_title,\n tts_results.raw_inference_text as maybe_descriptive_text_tts_result_inference_text,\n users.display_name as maybe_descriptive_text_user_display_name,\n voice_conversion_models.title as maybe_descriptive_text_voice_conversion_model_title,\n zs_voices.title as maybe_descriptive_text_zs_voice_title\n\nFROM\n user_bookmarks AS f\nJOIN users AS u\n ON f.user_token = u.token\n\nLEFT OUTER JOIN media_files ON media_files.token = f.entity_token\nLEFT OUTER JOIN tts_models ON tts_models.token = f.entity_token\nLEFT OUTER JOIN tts_results ON tts_results.token = f.entity_token\nLEFT OUTER JOIN users ON users.token = f.entity_token\nLEFT OUTER JOIN voice_conversion_models ON voice_conversion_models.token = f.entity_token\nLEFT OUTER JOIN zs_voices ON zs_voices.token = f.entity_token\n\nWHERE\n u.username = ?\n AND f.entity_type = ?\n AND f.deleted_at IS NULL\nORDER BY f.id DESC\nLIMIT 50\n ", + "query": "\nSELECT\n f.token as `token: tokens::tokens::user_bookmarks::UserBookmarkToken`,\n f.entity_type as `entity_type: enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType`,\n f.entity_token,\n f.user_token as `user_token: tokens::tokens::users::UserToken`,\n u.username,\n u.display_name as user_display_name,\n u.email_gravatar_hash as user_gravatar_hash,\n f.created_at,\n f.updated_at,\n f.deleted_at,\n\n media_files.media_type as `maybe_media_file_type: enums::by_table::media_files::media_file_type::MediaFileType`,\n media_files.origin_product_category as `maybe_media_file_origin_category: enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory`,\n\n model_weights.title as maybe_descriptive_text_model_weight_title,\n tts_models.title as maybe_descriptive_text_tts_model_title,\n tts_results.raw_inference_text as maybe_descriptive_text_tts_result_inference_text,\n users.display_name as maybe_descriptive_text_user_display_name,\n voice_conversion_models.title as maybe_descriptive_text_voice_conversion_model_title,\n zs_voices.title as maybe_descriptive_text_zs_voice_title\n\nFROM\n user_bookmarks AS f\nJOIN users AS u\n ON f.user_token = u.token\n\nLEFT OUTER JOIN model_weights ON model_weights.token = f.entity_token\nLEFT OUTER JOIN media_files ON media_files.token = f.entity_token\nLEFT OUTER JOIN tts_models ON tts_models.token = f.entity_token\nLEFT OUTER JOIN tts_results ON tts_results.token = f.entity_token\nLEFT OUTER JOIN users ON users.token = f.entity_token\nLEFT OUTER JOIN voice_conversion_models ON voice_conversion_models.token = f.entity_token\nLEFT OUTER JOIN zs_voices ON zs_voices.token = f.entity_token\n\nWHERE\n u.username = ?\n AND f.entity_type = ?\n AND f.deleted_at IS NULL\nORDER BY f.id DESC\nLIMIT 50\n ", "describe": { "columns": [ { @@ -125,7 +125,7 @@ }, { "ordinal": 12, - "name": "maybe_descriptive_text_tts_model_title", + "name": "maybe_descriptive_text_model_weight_title", "type_info": { "type": "VarString", "flags": "BINARY | NO_DEFAULT_VALUE", @@ -135,6 +135,16 @@ }, { "ordinal": 13, + "name": "maybe_descriptive_text_tts_model_title", + "type_info": { + "type": "VarString", + "flags": "BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 1020 + } + }, + { + "ordinal": 14, "name": "maybe_descriptive_text_tts_result_inference_text", "type_info": { "type": "Blob", @@ -144,7 +154,7 @@ } }, { - "ordinal": 14, + "ordinal": 15, "name": "maybe_descriptive_text_user_display_name", "type_info": { "type": "VarString", @@ -154,7 +164,7 @@ } }, { - "ordinal": 15, + "ordinal": 16, "name": "maybe_descriptive_text_voice_conversion_model_title", "type_info": { "type": "VarString", @@ -164,7 +174,7 @@ } }, { - "ordinal": 16, + "ordinal": 17, "name": "maybe_descriptive_text_zs_voice_title", "type_info": { "type": "VarString", @@ -194,8 +204,9 @@ true, true, true, + true, true ] }, - "hash": "d9c00b3c78ed6ec31b281c7ea5fb1efd0cfa6b20899151f9e7f1a122c1f7a70e" + "hash": "3a7ac7f979ac270dad1070031d0d663d0eb3d969365f6b2fd048ca41c5c455b2" } diff --git a/.sqlx/query-eea9531d5261833b93baadee8b99449362c074fc2397e23ecd175b6a0425b16b.json b/.sqlx/query-707af35ee4ab4519f28e6d69982944666e6c7c0f24b5da79dde828ffdb2c8302.json similarity index 79% rename from .sqlx/query-eea9531d5261833b93baadee8b99449362c074fc2397e23ecd175b6a0425b16b.json rename to .sqlx/query-707af35ee4ab4519f28e6d69982944666e6c7c0f24b5da79dde828ffdb2c8302.json index 55d497beee..0b00758da8 100644 --- a/.sqlx/query-eea9531d5261833b93baadee8b99449362c074fc2397e23ecd175b6a0425b16b.json +++ b/.sqlx/query-707af35ee4ab4519f28e6d69982944666e6c7c0f24b5da79dde828ffdb2c8302.json @@ -1,6 +1,6 @@ { "db_name": "MySQL", - "query": "\nSELECT\n f.token as `token: tokens::tokens::user_bookmarks::UserBookmarkToken`,\n f.entity_type as `entity_type: enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType`,\n f.entity_token,\n f.user_token as `user_token: tokens::tokens::users::UserToken`,\n u.username,\n u.display_name as user_display_name,\n u.email_gravatar_hash as user_gravatar_hash,\n f.created_at,\n f.updated_at,\n f.deleted_at,\n\n media_files.media_type as `maybe_media_file_type: enums::by_table::media_files::media_file_type::MediaFileType`,\n media_files.origin_product_category as `maybe_media_file_origin_category: enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory`,\n\n tts_models.title as maybe_descriptive_text_tts_model_title,\n tts_results.raw_inference_text as maybe_descriptive_text_tts_result_inference_text,\n users.display_name as maybe_descriptive_text_user_display_name,\n voice_conversion_models.title as maybe_descriptive_text_voice_conversion_model_title,\n zs_voices.title as maybe_descriptive_text_zs_voice_title\n\nFROM\n user_bookmarks AS f\nJOIN users AS u\n ON f.user_token = u.token\n\nLEFT OUTER JOIN media_files ON media_files.token = f.entity_token\nLEFT OUTER JOIN tts_models ON tts_models.token = f.entity_token\nLEFT OUTER JOIN tts_results ON tts_results.token = f.entity_token\nLEFT OUTER JOIN users ON users.token = f.entity_token\nLEFT OUTER JOIN voice_conversion_models ON voice_conversion_models.token = f.entity_token\nLEFT OUTER JOIN zs_voices ON zs_voices.token = f.entity_token\n\nWHERE\n u.username = ?\n AND f.deleted_at IS NULL\nORDER BY f.id DESC\nLIMIT 50\n ", + "query": "\nSELECT\n f.token as `token: tokens::tokens::user_bookmarks::UserBookmarkToken`,\n f.entity_type as `entity_type: enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType`,\n f.entity_token,\n f.user_token as `user_token: tokens::tokens::users::UserToken`,\n u.username,\n u.display_name as user_display_name,\n u.email_gravatar_hash as user_gravatar_hash,\n f.created_at,\n f.updated_at,\n f.deleted_at,\n\n media_files.media_type as `maybe_media_file_type: enums::by_table::media_files::media_file_type::MediaFileType`,\n media_files.origin_product_category as `maybe_media_file_origin_category: enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory`,\n\n model_weights.title as maybe_descriptive_text_model_weight_title,\n tts_models.title as maybe_descriptive_text_tts_model_title,\n tts_results.raw_inference_text as maybe_descriptive_text_tts_result_inference_text,\n users.display_name as maybe_descriptive_text_user_display_name,\n voice_conversion_models.title as maybe_descriptive_text_voice_conversion_model_title,\n zs_voices.title as maybe_descriptive_text_zs_voice_title\n\nFROM\n user_bookmarks AS f\nJOIN users AS u\n ON f.user_token = u.token\n\nLEFT OUTER JOIN model_weights ON model_weights.token = f.entity_token\nLEFT OUTER JOIN media_files ON media_files.token = f.entity_token\nLEFT OUTER JOIN tts_models ON tts_models.token = f.entity_token\nLEFT OUTER JOIN tts_results ON tts_results.token = f.entity_token\nLEFT OUTER JOIN users ON users.token = f.entity_token\nLEFT OUTER JOIN voice_conversion_models ON voice_conversion_models.token = f.entity_token\nLEFT OUTER JOIN zs_voices ON zs_voices.token = f.entity_token\n\nWHERE\n u.username = ?\n AND f.deleted_at IS NULL\nORDER BY f.id DESC\nLIMIT 50\n ", "describe": { "columns": [ { @@ -125,7 +125,7 @@ }, { "ordinal": 12, - "name": "maybe_descriptive_text_tts_model_title", + "name": "maybe_descriptive_text_model_weight_title", "type_info": { "type": "VarString", "flags": "BINARY | NO_DEFAULT_VALUE", @@ -135,6 +135,16 @@ }, { "ordinal": 13, + "name": "maybe_descriptive_text_tts_model_title", + "type_info": { + "type": "VarString", + "flags": "BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 1020 + } + }, + { + "ordinal": 14, "name": "maybe_descriptive_text_tts_result_inference_text", "type_info": { "type": "Blob", @@ -144,7 +154,7 @@ } }, { - "ordinal": 14, + "ordinal": 15, "name": "maybe_descriptive_text_user_display_name", "type_info": { "type": "VarString", @@ -154,7 +164,7 @@ } }, { - "ordinal": 15, + "ordinal": 16, "name": "maybe_descriptive_text_voice_conversion_model_title", "type_info": { "type": "VarString", @@ -164,7 +174,7 @@ } }, { - "ordinal": 16, + "ordinal": 17, "name": "maybe_descriptive_text_zs_voice_title", "type_info": { "type": "VarString", @@ -194,8 +204,9 @@ true, true, true, + true, true ] }, - "hash": "eea9531d5261833b93baadee8b99449362c074fc2397e23ecd175b6a0425b16b" + "hash": "707af35ee4ab4519f28e6d69982944666e6c7c0f24b5da79dde828ffdb2c8302" } diff --git a/crates/lib/mysql_queries/src/queries/media_files/list_media_files_by_tokens.rs b/crates/lib/mysql_queries/src/queries/media_files/list_media_files_by_tokens.rs new file mode 100644 index 0000000000..f08a9534a9 --- /dev/null +++ b/crates/lib/mysql_queries/src/queries/media_files/list_media_files_by_tokens.rs @@ -0,0 +1,264 @@ +use chrono::{DateTime, Utc}; +use sqlx::{Acquire, FromRow, MySql, MySqlConnection, MySqlPool, QueryBuilder, Row}; +use sqlx::mysql::MySqlRow; + +use enums::by_table::model_weights::{ + weights_category::WeightsCategory, + weights_types::WeightsType, +}; +use enums::traits::mysql_from_row::MySqlFromRow; +use errors::AnyhowResult; +use tokens::tokens::model_weights::ModelWeightToken; +use tokens::tokens::users::UserToken; + +#[derive(Serialize)] +pub struct WeightsByTokensRecord { + pub token: ModelWeightToken, + + pub weights_type: WeightsType, + pub weights_category: WeightsCategory, + + pub title: String, + + pub maybe_thumbnail_token: Option, + + pub creator_user_token: UserToken, + pub creator_username: String, + pub creator_display_name: String, + pub creator_email_gravatar_hash: String, + + pub private_bucket_hash: String, + pub maybe_private_bucket_prefix: Option, + pub maybe_private_bucket_extension: Option, + + pub cached_user_ratings_total_count: u32, + pub cached_user_ratings_positive_count: u32, + pub cached_user_ratings_negative_count: u32, + pub maybe_cached_user_ratings_ratio: Option, + pub cached_user_ratings_last_updated_at: DateTime, + + pub created_at: DateTime, + pub updated_at: DateTime, + pub user_deleted_at: Option>, + pub mod_deleted_at: Option>, +} + +pub async fn list_weights_by_tokens( + mysql_pool: &MySqlPool, + weight_tokens: &[ModelWeightToken], + can_see_deleted: bool +) -> AnyhowResult> { + + let mut connection = mysql_pool.acquire().await?; + + let raw_weights: Vec = get_raw_weights_by_tokens(&mut connection, weight_tokens, can_see_deleted).await?; + + Ok(map_to_weights(raw_weights)) +} + +async fn get_raw_weights_by_tokens( + connection: &mut MySqlConnection, + weight_tokens: &[ModelWeightToken], + can_see_deleted: bool +) -> AnyhowResult> { + + let connection = connection.acquire().await?; + + let mut query_builder : QueryBuilder = if can_see_deleted { + QueryBuilder::new(r#" + SELECT + mw.token, + mw.title, + mw.weights_type, + mw.weights_category, + mw.maybe_thumbnail_token, + users.token as creator_user_token, + users.username as creator_username, + users.display_name as creator_display_name, + users.email_gravatar_hash as creator_email_gravatar_hash, + mw.private_bucket_hash, + mw.maybe_private_bucket_prefix, + mw.maybe_private_bucket_extension, + mw.cached_user_ratings_negative_count, + mw.cached_user_ratings_positive_count, + mw.cached_user_ratings_total_count, + mw.maybe_cached_user_ratings_ratio, + mw.cached_user_ratings_last_updated_at, + mw.created_at, + mw.updated_at, + mw.user_deleted_at, + mw.mod_deleted_at + FROM model_weights as mw + JOIN users + ON users.token = mw.creator_user_token + WHERE + mw.creator_set_visibility = "public" + AND mw.token IN ( + "#, + ) + + } else { + QueryBuilder::new(r#" + SELECT + mw.token, + mw.title, + mw.weights_type, + mw.weights_category, + mw.maybe_thumbnail_token, + users.token as creator_user_token, + users.username as creator_username, + users.display_name as creator_display_name, + users.email_gravatar_hash as creator_email_gravatar_hash, + mw.private_bucket_hash, + mw.maybe_private_bucket_prefix, + mw.maybe_private_bucket_extension, + mw.cached_user_ratings_negative_count, + mw.cached_user_ratings_positive_count, + mw.cached_user_ratings_total_count, + mw.maybe_cached_user_ratings_ratio, + mw.cached_user_ratings_last_updated_at, + mw.created_at, + mw.updated_at, + mw.user_deleted_at, + mw.mod_deleted_at + FROM model_weights as mw + JOIN users + ON users.token = mw.creator_user_token + WHERE + mw.creator_set_visibility = "public" + AND mw.user_deleted_at IS NULL + AND mw.mod_deleted_at IS NULL + AND mw.token IN ( + "# + ) + }; + + query_builder.push(token_predicate(weight_tokens)); + + query_builder.push(")"); + + let query = query_builder.build_query_as::(); + + let results = query.fetch_all(connection).await?; + + Ok(results) +} + +/// Return a comma-separated predicate, since SQLx does not yet support WHERE IN(?) for Vec, etc. +/// Issue: https://github.com/launchbadge/sqlx/issues/875 +fn token_predicate(tokens: &[ModelWeightToken]) -> String { + tokens.iter() + .map(|ty| ty.as_str()) + .map(|ty| format!("\"{}\"", ty)) + .collect::>() + .join(", ") +} + +fn map_to_weights(dataset:Vec) -> Vec { + let weights: Vec = dataset + .into_iter() + .map(|dataset: RawWeightJoinUser| { + WeightsByTokensRecord { + token: dataset.token, + title: dataset.title, + weights_type: dataset.weights_type, + weights_category: dataset.weights_category, + maybe_thumbnail_token: dataset.maybe_thumbnail_token, + + creator_user_token: dataset.creator_user_token, + creator_username:dataset.creator_username, + creator_display_name:dataset.creator_display_name, + creator_email_gravatar_hash:dataset.creator_email_gravatar_hash, + + private_bucket_hash: dataset.private_bucket_hash, + maybe_private_bucket_prefix: dataset.maybe_private_bucket_prefix, + maybe_private_bucket_extension: dataset.maybe_private_bucket_extension, + + cached_user_ratings_negative_count: dataset.cached_user_ratings_negative_count, + cached_user_ratings_positive_count: dataset.cached_user_ratings_positive_count, + cached_user_ratings_total_count: dataset.cached_user_ratings_total_count, + + maybe_cached_user_ratings_ratio: dataset.maybe_cached_user_ratings_ratio, + cached_user_ratings_last_updated_at: dataset.cached_user_ratings_last_updated_at, + + created_at: dataset.created_at, + updated_at: dataset.updated_at, + user_deleted_at: dataset.user_deleted_at, + mod_deleted_at: dataset.mod_deleted_at, + } + }).collect(); + + weights +} + + #[derive(Serialize)] + pub struct RawWeightJoinUser { + pub token: ModelWeightToken, + + pub weights_type: WeightsType, + pub weights_category: WeightsCategory, + + pub title: String, + + pub maybe_thumbnail_token: Option, + + pub creator_user_token: UserToken, + pub creator_username: String, + pub creator_display_name: String, + pub creator_email_gravatar_hash: String, + + pub private_bucket_hash: String, + pub maybe_private_bucket_prefix: Option, + pub maybe_private_bucket_extension: Option, + + pub cached_user_ratings_total_count: u32, + pub cached_user_ratings_positive_count: u32, + pub cached_user_ratings_negative_count: u32, + pub maybe_cached_user_ratings_ratio: Option, + pub cached_user_ratings_last_updated_at: DateTime, + + pub created_at: DateTime, + pub updated_at: DateTime, + pub user_deleted_at: Option>, + pub mod_deleted_at: Option>, +} + +// NB(bt,2023-12-05): There's an issue with type hinting in the `as` clauses with QueryBuilder (or +// raw query strings) and sqlx::FromRow, regardless of whether it is derived of manually +// implemented. Perhaps this will improve in the future, but for now manually constructed queries +// cannot have type hints, eg. the following: +// +// m.token as `token: tokens::tokens::media_files::MediaFileToken`, +// m.origin_category as `origin_category: enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory`, +// m.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`, +// +// This results in the automatic mapping not being able to be found by name (for macro derive), and +// in the manual case `row.try_get()` etc. won't have the correct column name (since the name is the +// full "as" clause). +impl FromRow<'_, MySqlRow> for RawWeightJoinUser { + fn from_row(row: &MySqlRow) -> Result { + Ok(Self { + token: ModelWeightToken::new(row.try_get("token")?), + weights_type: WeightsType::try_from_mysql_row(row, "weights_type")?, + weights_category: WeightsCategory::try_from_mysql_row(row, "weights_category")?, + title: row.try_get("title")?, + maybe_thumbnail_token: row.try_get("maybe_thumbnail_token")?, + creator_user_token: UserToken::new_from_str(row.try_get("creator_user_token")?), + creator_username: row.try_get("creator_username")?, + creator_display_name: row.try_get("creator_display_name")?, + creator_email_gravatar_hash: row.try_get("creator_email_gravatar_hash")?, + private_bucket_hash: row.try_get("private_bucket_hash")?, + maybe_private_bucket_prefix: row.try_get("maybe_private_bucket_prefix")?, + maybe_private_bucket_extension: row.try_get("maybe_private_bucket_extension")?, + cached_user_ratings_total_count: row.try_get("cached_user_ratings_total_count")?, + cached_user_ratings_positive_count: row.try_get("cached_user_ratings_positive_count")?, + cached_user_ratings_negative_count: row.try_get("cached_user_ratings_negative_count")?, + maybe_cached_user_ratings_ratio: row.try_get("maybe_cached_user_ratings_ratio")?, + cached_user_ratings_last_updated_at: row.try_get("cached_user_ratings_last_updated_at")?, + created_at: row.try_get("created_at")?, + updated_at: row.try_get("updated_at")?, + user_deleted_at: row.try_get("user_deleted_at")?, + mod_deleted_at: row.try_get("mod_deleted_at")?, + }) + } +} From 32b1786b59c8456ea382c511ab50b9be1d906d35 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Thu, 14 Dec 2023 14:53:17 -0500 Subject: [PATCH 042/124] No hateful / antisemitic models on our service (hitler) --- _sql/actions/voice_conversion_models.sql | 9 +++++++++ crates/lib/mysql_queries/src/queries/media_files/mod.rs | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/_sql/actions/voice_conversion_models.sql b/_sql/actions/voice_conversion_models.sql index 1c040d57da..7f97f2da68 100644 --- a/_sql/actions/voice_conversion_models.sql +++ b/_sql/actions/voice_conversion_models.sql @@ -376,6 +376,15 @@ where token IN ( ); +update voice_conversion_models +set + mod_deleted_at = NOW(), + maybe_mod_comments = 'abuse' +where token IN ( + 'vcm_qajyd528p8kw', + 'vcm_f5pcdecmzcc5' +); + diff --git a/crates/lib/mysql_queries/src/queries/media_files/mod.rs b/crates/lib/mysql_queries/src/queries/media_files/mod.rs index ff431d1cb4..cedc16583c 100644 --- a/crates/lib/mysql_queries/src/queries/media_files/mod.rs +++ b/crates/lib/mysql_queries/src/queries/media_files/mod.rs @@ -2,10 +2,11 @@ pub mod delete_media_file; pub mod get_media_file; pub mod insert_media_file_from_cli_tool; pub mod insert_media_file_from_face_animation; +pub mod insert_media_file_from_rerender; pub mod insert_media_file_from_tacotron2; pub mod insert_media_file_from_voice_conversion; pub mod insert_media_file_from_zero_shot_tts; pub mod list_media_files; +pub mod list_media_files_by_tokens; pub mod list_media_files_for_user; pub mod update_media_file; -pub mod insert_media_file_from_rerender; From 5a4d2a8c065e208f994749ddf421ff715e347b72 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Thu, 14 Dec 2023 15:15:31 -0500 Subject: [PATCH 043/124] media files query by tokens (WHERE IN clause) --- .../media_files/list_media_files_by_tokens.rs | 296 ++++++++---------- 1 file changed, 132 insertions(+), 164 deletions(-) diff --git a/crates/lib/mysql_queries/src/queries/media_files/list_media_files_by_tokens.rs b/crates/lib/mysql_queries/src/queries/media_files/list_media_files_by_tokens.rs index f08a9534a9..a6e06e49f8 100644 --- a/crates/lib/mysql_queries/src/queries/media_files/list_media_files_by_tokens.rs +++ b/crates/lib/mysql_queries/src/queries/media_files/list_media_files_by_tokens.rs @@ -2,142 +2,131 @@ use chrono::{DateTime, Utc}; use sqlx::{Acquire, FromRow, MySql, MySqlConnection, MySqlPool, QueryBuilder, Row}; use sqlx::mysql::MySqlRow; -use enums::by_table::model_weights::{ - weights_category::WeightsCategory, - weights_types::WeightsType, -}; +use enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory; +use enums::by_table::media_files::media_file_origin_model_type::MediaFileOriginModelType; +use enums::by_table::media_files::media_file_origin_product_category::MediaFileOriginProductCategory; +use enums::by_table::media_files::media_file_type::MediaFileType; use enums::traits::mysql_from_row::MySqlFromRow; use errors::AnyhowResult; -use tokens::tokens::model_weights::ModelWeightToken; +use tokens::tokens::media_files::MediaFileToken; use tokens::tokens::users::UserToken; #[derive(Serialize)] -pub struct WeightsByTokensRecord { - pub token: ModelWeightToken, +pub struct MediaFilesByTokensRecord { + pub token: MediaFileToken, - pub weights_type: WeightsType, - pub weights_category: WeightsCategory, + pub origin_category: MediaFileOriginCategory, + pub origin_product_category: MediaFileOriginProductCategory, + pub maybe_origin_model_type: Option, + pub maybe_origin_model_token: Option, - pub title: String, + pub media_type: MediaFileType, + pub public_bucket_directory_hash: String, + pub maybe_public_bucket_prefix: Option, + pub maybe_public_bucket_extension: Option, - pub maybe_thumbnail_token: Option, - - pub creator_user_token: UserToken, - pub creator_username: String, - pub creator_display_name: String, - pub creator_email_gravatar_hash: String, - - pub private_bucket_hash: String, - pub maybe_private_bucket_prefix: Option, - pub maybe_private_bucket_extension: Option, - - pub cached_user_ratings_total_count: u32, - pub cached_user_ratings_positive_count: u32, - pub cached_user_ratings_negative_count: u32, - pub maybe_cached_user_ratings_ratio: Option, - pub cached_user_ratings_last_updated_at: DateTime, + pub maybe_creator_user_token: Option, + pub maybe_creator_username: Option, + pub maybe_creator_display_name: Option, + pub maybe_creator_email_gravatar_hash: Option, pub created_at: DateTime, pub updated_at: DateTime, - pub user_deleted_at: Option>, - pub mod_deleted_at: Option>, } -pub async fn list_weights_by_tokens( +pub async fn list_media_files_by_tokens( mysql_pool: &MySqlPool, - weight_tokens: &[ModelWeightToken], + media_file_tokens: &[MediaFileToken], can_see_deleted: bool -) -> AnyhowResult> { +) -> AnyhowResult> { let mut connection = mysql_pool.acquire().await?; - let raw_weights: Vec = get_raw_weights_by_tokens(&mut connection, weight_tokens, can_see_deleted).await?; + let raw_media_files: Vec = get_raw_media_files_by_tokens(&mut connection, media_file_tokens, can_see_deleted).await?; - Ok(map_to_weights(raw_weights)) + Ok(map_to_media_files(raw_media_files)) } -async fn get_raw_weights_by_tokens( +async fn get_raw_media_files_by_tokens( connection: &mut MySqlConnection, - weight_tokens: &[ModelWeightToken], + media_file_tokens: &[MediaFileToken], can_see_deleted: bool -) -> AnyhowResult> { +) -> AnyhowResult> { let connection = connection.acquire().await?; let mut query_builder : QueryBuilder = if can_see_deleted { QueryBuilder::new(r#" SELECT - mw.token, - mw.title, - mw.weights_type, - mw.weights_category, - mw.maybe_thumbnail_token, - users.token as creator_user_token, - users.username as creator_username, - users.display_name as creator_display_name, - users.email_gravatar_hash as creator_email_gravatar_hash, - mw.private_bucket_hash, - mw.maybe_private_bucket_prefix, - mw.maybe_private_bucket_extension, - mw.cached_user_ratings_negative_count, - mw.cached_user_ratings_positive_count, - mw.cached_user_ratings_total_count, - mw.maybe_cached_user_ratings_ratio, - mw.cached_user_ratings_last_updated_at, - mw.created_at, - mw.updated_at, - mw.user_deleted_at, - mw.mod_deleted_at - FROM model_weights as mw - JOIN users - ON users.token = mw.creator_user_token + m.token, + + m.origin_category, + m.origin_product_category, + m.maybe_origin_model_type, + m.maybe_origin_model_token, + + users.token as maybe_creator_user_token, + users.username as maybe_creator_username, + users.display_name as maybe_creator_display_name, + users.email_gravatar_hash as maybe_creator_email_gravatar_hash, + + m.media_type, + m.public_bucket_directory_hash, + m.maybe_public_bucket_prefix, + m.maybe_public_bucket_extension, + + m.created_at, + m.updated_at + + FROM media_files as m + LEFT OUTER JOIN users + ON users.token = m.maybe_creator_user_token WHERE - mw.creator_set_visibility = "public" - AND mw.token IN ( + m.creator_set_visibility = "public" + AND m.token IN ( "#, ) } else { QueryBuilder::new(r#" SELECT - mw.token, - mw.title, - mw.weights_type, - mw.weights_category, - mw.maybe_thumbnail_token, - users.token as creator_user_token, - users.username as creator_username, - users.display_name as creator_display_name, - users.email_gravatar_hash as creator_email_gravatar_hash, - mw.private_bucket_hash, - mw.maybe_private_bucket_prefix, - mw.maybe_private_bucket_extension, - mw.cached_user_ratings_negative_count, - mw.cached_user_ratings_positive_count, - mw.cached_user_ratings_total_count, - mw.maybe_cached_user_ratings_ratio, - mw.cached_user_ratings_last_updated_at, - mw.created_at, - mw.updated_at, - mw.user_deleted_at, - mw.mod_deleted_at - FROM model_weights as mw - JOIN users - ON users.token = mw.creator_user_token + m.token, + + m.origin_category, + m.origin_product_category, + m.maybe_origin_model_type, + m.maybe_origin_model_token, + + users.token as maybe_creator_user_token, + users.username as maybe_creator_username, + users.display_name as maybe_creator_display_name, + users.email_gravatar_hash as maybe_creator_email_gravatar_hash, + + m.media_type, + m.public_bucket_directory_hash, + m.maybe_public_bucket_prefix, + m.maybe_public_bucket_extension, + + m.created_at, + m.updated_at + + FROM media_files as m + LEFT OUTER JOIN users + ON users.token = m.maybe_creator_user_token WHERE - mw.creator_set_visibility = "public" - AND mw.user_deleted_at IS NULL - AND mw.mod_deleted_at IS NULL - AND mw.token IN ( + m.creator_set_visibility = "public" + AND m.user_deleted_at IS NULL + AND m.mod_deleted_at IS NULL + AND m.token IN ( "# ) }; - query_builder.push(token_predicate(weight_tokens)); + query_builder.push(token_predicate(media_file_tokens)); query_builder.push(")"); - let query = query_builder.build_query_as::(); + let query = query_builder.build_query_as::(); let results = query.fetch_all(connection).await?; @@ -146,7 +135,7 @@ async fn get_raw_weights_by_tokens( /// Return a comma-separated predicate, since SQLx does not yet support WHERE IN(?) for Vec, etc. /// Issue: https://github.com/launchbadge/sqlx/issues/875 -fn token_predicate(tokens: &[ModelWeightToken]) -> String { +fn token_predicate(tokens: &[MediaFileToken]) -> String { tokens.iter() .map(|ty| ty.as_str()) .map(|ty| format!("\"{}\"", ty)) @@ -154,73 +143,57 @@ fn token_predicate(tokens: &[ModelWeightToken]) -> String { .join(", ") } -fn map_to_weights(dataset:Vec) -> Vec { - let weights: Vec = dataset +fn map_to_media_files(dataset:Vec) -> Vec { + let media_files: Vec = dataset .into_iter() - .map(|dataset: RawWeightJoinUser| { - WeightsByTokensRecord { - token: dataset.token, - title: dataset.title, - weights_type: dataset.weights_type, - weights_category: dataset.weights_category, - maybe_thumbnail_token: dataset.maybe_thumbnail_token, + .map(|media_file: RawMediaFileJoinUser| { + MediaFilesByTokensRecord { + token: media_file.token, - creator_user_token: dataset.creator_user_token, - creator_username:dataset.creator_username, - creator_display_name:dataset.creator_display_name, - creator_email_gravatar_hash:dataset.creator_email_gravatar_hash, + origin_category: media_file.origin_category, + origin_product_category: media_file.origin_product_category, + maybe_origin_model_type: media_file.maybe_origin_model_type, + maybe_origin_model_token: media_file.maybe_origin_model_token, - private_bucket_hash: dataset.private_bucket_hash, - maybe_private_bucket_prefix: dataset.maybe_private_bucket_prefix, - maybe_private_bucket_extension: dataset.maybe_private_bucket_extension, + maybe_creator_user_token: media_file.maybe_creator_user_token, + maybe_creator_username: media_file.maybe_creator_username, + maybe_creator_display_name: media_file.maybe_creator_display_name, + maybe_creator_email_gravatar_hash: media_file.maybe_creator_email_gravatar_hash, - cached_user_ratings_negative_count: dataset.cached_user_ratings_negative_count, - cached_user_ratings_positive_count: dataset.cached_user_ratings_positive_count, - cached_user_ratings_total_count: dataset.cached_user_ratings_total_count, + media_type: media_file.media_type, + public_bucket_directory_hash: media_file.public_bucket_directory_hash, + maybe_public_bucket_prefix: media_file.maybe_public_bucket_prefix, + maybe_public_bucket_extension: media_file.maybe_public_bucket_extension, - maybe_cached_user_ratings_ratio: dataset.maybe_cached_user_ratings_ratio, - cached_user_ratings_last_updated_at: dataset.cached_user_ratings_last_updated_at, - - created_at: dataset.created_at, - updated_at: dataset.updated_at, - user_deleted_at: dataset.user_deleted_at, - mod_deleted_at: dataset.mod_deleted_at, + created_at: media_file.created_at, + updated_at: media_file.updated_at, } }).collect(); - weights + media_files } #[derive(Serialize)] - pub struct RawWeightJoinUser { - pub token: ModelWeightToken, + pub struct RawMediaFileJoinUser { + pub token: MediaFileToken, - pub weights_type: WeightsType, - pub weights_category: WeightsCategory, - - pub title: String, - - pub maybe_thumbnail_token: Option, + pub origin_category: MediaFileOriginCategory, + pub origin_product_category: MediaFileOriginProductCategory, + pub maybe_origin_model_type: Option, + pub maybe_origin_model_token: Option, - pub creator_user_token: UserToken, - pub creator_username: String, - pub creator_display_name: String, - pub creator_email_gravatar_hash: String, + pub maybe_creator_user_token: Option, + pub maybe_creator_username: Option, + pub maybe_creator_display_name: Option, + pub maybe_creator_email_gravatar_hash: Option, + + pub media_type: MediaFileType, + pub public_bucket_directory_hash: String, + pub maybe_public_bucket_prefix: Option, + pub maybe_public_bucket_extension: Option, - pub private_bucket_hash: String, - pub maybe_private_bucket_prefix: Option, - pub maybe_private_bucket_extension: Option, - - pub cached_user_ratings_total_count: u32, - pub cached_user_ratings_positive_count: u32, - pub cached_user_ratings_negative_count: u32, - pub maybe_cached_user_ratings_ratio: Option, - pub cached_user_ratings_last_updated_at: DateTime, - pub created_at: DateTime, pub updated_at: DateTime, - pub user_deleted_at: Option>, - pub mod_deleted_at: Option>, } // NB(bt,2023-12-05): There's an issue with type hinting in the `as` clauses with QueryBuilder (or @@ -235,30 +208,25 @@ fn map_to_weights(dataset:Vec) -> Vec // This results in the automatic mapping not being able to be found by name (for macro derive), and // in the manual case `row.try_get()` etc. won't have the correct column name (since the name is the // full "as" clause). -impl FromRow<'_, MySqlRow> for RawWeightJoinUser { +impl FromRow<'_, MySqlRow> for RawMediaFileJoinUser { fn from_row(row: &MySqlRow) -> Result { Ok(Self { - token: ModelWeightToken::new(row.try_get("token")?), - weights_type: WeightsType::try_from_mysql_row(row, "weights_type")?, - weights_category: WeightsCategory::try_from_mysql_row(row, "weights_category")?, - title: row.try_get("title")?, - maybe_thumbnail_token: row.try_get("maybe_thumbnail_token")?, - creator_user_token: UserToken::new_from_str(row.try_get("creator_user_token")?), - creator_username: row.try_get("creator_username")?, - creator_display_name: row.try_get("creator_display_name")?, - creator_email_gravatar_hash: row.try_get("creator_email_gravatar_hash")?, - private_bucket_hash: row.try_get("private_bucket_hash")?, - maybe_private_bucket_prefix: row.try_get("maybe_private_bucket_prefix")?, - maybe_private_bucket_extension: row.try_get("maybe_private_bucket_extension")?, - cached_user_ratings_total_count: row.try_get("cached_user_ratings_total_count")?, - cached_user_ratings_positive_count: row.try_get("cached_user_ratings_positive_count")?, - cached_user_ratings_negative_count: row.try_get("cached_user_ratings_negative_count")?, - maybe_cached_user_ratings_ratio: row.try_get("maybe_cached_user_ratings_ratio")?, - cached_user_ratings_last_updated_at: row.try_get("cached_user_ratings_last_updated_at")?, + token: MediaFileToken::new(row.try_get("token")?), + origin_category: MediaFileOriginCategory::try_from_mysql_row(row, "origin_category")?, + origin_product_category: MediaFileOriginProductCategory::try_from_mysql_row(row, "origin_product_category")?, + maybe_origin_model_type: MediaFileOriginModelType::try_from_mysql_row_nullable(row, "maybe_origin_model_type")?, + maybe_origin_model_token: row.try_get("maybe_origin_model_token")?, + maybe_creator_user_token: row.try_get::, _>("maybe_creator_user_token")? + .and_then(|token| Some(UserToken::new_from_str(&token))), + maybe_creator_username: row.try_get("maybe_creator_username")?, + maybe_creator_display_name: row.try_get("maybe_creator_display_name")?, + maybe_creator_email_gravatar_hash: row.try_get("maybe_creator_email_gravatar_hash")?, + media_type: MediaFileType::try_from_mysql_row(row, "media_type")?, + public_bucket_directory_hash: row.try_get("public_bucket_directory_hash")?, + maybe_public_bucket_prefix: row.try_get("maybe_public_bucket_prefix")?, + maybe_public_bucket_extension: row.try_get("maybe_public_bucket_extension")?, created_at: row.try_get("created_at")?, updated_at: row.try_get("updated_at")?, - user_deleted_at: row.try_get("user_deleted_at")?, - mod_deleted_at: row.try_get("mod_deleted_at")?, }) } } From a88d888c18cb4f51e4d5e2bff9ee3b25b44281b5 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Thu, 14 Dec 2023 16:35:07 -0500 Subject: [PATCH 044/124] featured media weights endpoint --- .../media_files/list_media_files_by_tokens.rs | 12 +- .../media_files/list_featured_media_files.rs | 170 ++++++++++++++++++ .../http_server/endpoints/media_files/mod.rs | 1 + .../service/web/storyteller_web/src/routes.rs | 5 + 4 files changed, 183 insertions(+), 5 deletions(-) create mode 100644 crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_featured_media_files.rs diff --git a/crates/lib/mysql_queries/src/queries/media_files/list_media_files_by_tokens.rs b/crates/lib/mysql_queries/src/queries/media_files/list_media_files_by_tokens.rs index a6e06e49f8..d55cf8be87 100644 --- a/crates/lib/mysql_queries/src/queries/media_files/list_media_files_by_tokens.rs +++ b/crates/lib/mysql_queries/src/queries/media_files/list_media_files_by_tokens.rs @@ -15,12 +15,13 @@ use tokens::tokens::users::UserToken; pub struct MediaFilesByTokensRecord { pub token: MediaFileToken, + pub media_type: MediaFileType, + pub origin_category: MediaFileOriginCategory, pub origin_product_category: MediaFileOriginProductCategory, pub maybe_origin_model_type: Option, pub maybe_origin_model_token: Option, - pub media_type: MediaFileType, pub public_bucket_directory_hash: String, pub maybe_public_bucket_prefix: Option, pub maybe_public_bucket_extension: Option, @@ -59,6 +60,7 @@ async fn get_raw_media_files_by_tokens( QueryBuilder::new(r#" SELECT m.token, + m.media_type, m.origin_category, m.origin_product_category, @@ -70,7 +72,6 @@ async fn get_raw_media_files_by_tokens( users.display_name as maybe_creator_display_name, users.email_gravatar_hash as maybe_creator_email_gravatar_hash, - m.media_type, m.public_bucket_directory_hash, m.maybe_public_bucket_prefix, m.maybe_public_bucket_extension, @@ -91,6 +92,7 @@ async fn get_raw_media_files_by_tokens( QueryBuilder::new(r#" SELECT m.token, + m.media_type, m.origin_category, m.origin_product_category, @@ -102,7 +104,6 @@ async fn get_raw_media_files_by_tokens( users.display_name as maybe_creator_display_name, users.email_gravatar_hash as maybe_creator_email_gravatar_hash, - m.media_type, m.public_bucket_directory_hash, m.maybe_public_bucket_prefix, m.maybe_public_bucket_extension, @@ -177,6 +178,8 @@ fn map_to_media_files(dataset:Vec) -> Vec, @@ -187,7 +190,6 @@ fn map_to_media_files(dataset:Vec) -> Vec, pub maybe_creator_email_gravatar_hash: Option, - pub media_type: MediaFileType, pub public_bucket_directory_hash: String, pub maybe_public_bucket_prefix: Option, pub maybe_public_bucket_extension: Option, @@ -212,6 +214,7 @@ impl FromRow<'_, MySqlRow> for RawMediaFileJoinUser { fn from_row(row: &MySqlRow) -> Result { Ok(Self { token: MediaFileToken::new(row.try_get("token")?), + media_type: MediaFileType::try_from_mysql_row(row, "media_type")?, origin_category: MediaFileOriginCategory::try_from_mysql_row(row, "origin_category")?, origin_product_category: MediaFileOriginProductCategory::try_from_mysql_row(row, "origin_product_category")?, maybe_origin_model_type: MediaFileOriginModelType::try_from_mysql_row_nullable(row, "maybe_origin_model_type")?, @@ -221,7 +224,6 @@ impl FromRow<'_, MySqlRow> for RawMediaFileJoinUser { maybe_creator_username: row.try_get("maybe_creator_username")?, maybe_creator_display_name: row.try_get("maybe_creator_display_name")?, maybe_creator_email_gravatar_hash: row.try_get("maybe_creator_email_gravatar_hash")?, - media_type: MediaFileType::try_from_mysql_row(row, "media_type")?, public_bucket_directory_hash: row.try_get("public_bucket_directory_hash")?, maybe_public_bucket_prefix: row.try_get("maybe_public_bucket_prefix")?, maybe_public_bucket_extension: row.try_get("maybe_public_bucket_extension")?, diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_featured_media_files.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_featured_media_files.rs new file mode 100644 index 0000000000..55cbfaef7b --- /dev/null +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_featured_media_files.rs @@ -0,0 +1,170 @@ +use std::sync::Arc; + +use actix_web::{HttpRequest, HttpResponse, web}; +use actix_web::error::ResponseError; +use actix_web::http::StatusCode; +use chrono::{DateTime, Utc}; +use log::{debug, error, warn}; +use r2d2_redis::redis::Commands; +use utoipa::ToSchema; +use buckets::public::media_files::bucket_file_path::MediaFileBucketPath; +use enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory; +use enums::by_table::media_files::media_file_origin_model_type::MediaFileOriginModelType; +use enums::by_table::media_files::media_file_origin_product_category::MediaFileOriginProductCategory; +use enums::by_table::media_files::media_file_type::MediaFileType; + +use enums::by_table::model_weights::{ + weights_category::WeightsCategory, + weights_types::WeightsType, +}; +use mysql_queries::queries::media_files::list_media_files_by_tokens::list_media_files_by_tokens; +use mysql_queries::queries::model_weights::list_weights_by_tokens::list_weights_by_tokens; +use tokens::tokens::media_files::MediaFileToken; +use tokens::tokens::model_weights::ModelWeightToken; + +use crate::http_server::common_responses::user_details_lite::UserDetailsLight; +use crate::server_state::ServerState; + +#[derive(Serialize, ToSchema)] +pub struct ListFeaturedMediaFilesSuccessResponse { + pub success: bool, + pub media_files: Vec, +} + +#[derive(Serialize, ToSchema)] +pub struct MediaFile { + pub token: MediaFileToken, + + /// Type of media will dictate which fields are populated and what + /// the frontend should display (eg. video player vs audio player). + pub media_type: MediaFileType, + + /// URL to the media file + pub public_bucket_path: String, + + // TODO: Provenance data - hide some of the models we use, especially zero shot. + //pub origin_category: MediaFileOriginCategory, + //pub origin_product_category: MediaFileOriginProductCategory, + //pub maybe_origin_model_type: Option, + //pub maybe_origin_model_token: Option, + + pub maybe_creator: Option, + + pub created_at: DateTime, + pub updated_at: DateTime, +} + +/// The key we store featured media file tokens under +const REDIS_KEY : &str = "featured_media_files_list"; + +#[derive(Debug, ToSchema)] +pub enum ListFeaturedMediaFilesError { + NotAuthorized, + ServerError, +} + +impl std::fmt::Display for ListFeaturedMediaFilesError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} + +impl ResponseError for ListFeaturedMediaFilesError { + fn status_code(&self) -> StatusCode { + match *self { + ListFeaturedMediaFilesError::NotAuthorized => StatusCode::UNAUTHORIZED, + ListFeaturedMediaFilesError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, + } + } +} + +#[utoipa::path( + get, + path = "/v1/media_files/list_featured", + responses( + (status = 200, description = "List Featured Media Files", body = ListFeaturedMediaFilesSuccessResponse), + (status = 401, description = "Not authorized", body = ListFeaturedMediaFilesError), + (status = 500, description = "Server error", body = ListFeaturedMediaFilesError), + ), +)] +pub async fn list_featured_media_files_handler( + http_request: HttpRequest, + server_state: web::Data> +) -> Result { + + let mut redis = server_state.redis_pool.get() + .map_err(|err| { + error!("Could not obtain redis: {err}"); + ListFeaturedMediaFilesError::ServerError + })?; + + let token_list : Option = redis.get(REDIS_KEY) + .map_err(|err| { + error!("Could not get redis result: {err}"); + ListFeaturedMediaFilesError::ServerError + })?; + + let media_file_tokens = token_list + .unwrap_or_else(|| "".to_string()) + .split(",") + .into_iter() + .map(|item| item.trim()) + .filter(|item| !item.is_empty()) + .map(|item| MediaFileToken::new_from_str(item)) + .collect::>(); + + debug!("Weight tokens from Redis: {:?}", media_file_tokens); + + let mut media_files = Vec::new(); + + if !media_file_tokens.is_empty() { + let query_results = + list_media_files_by_tokens(&server_state.mysql_pool, &media_file_tokens, false).await; + + media_files = match query_results { + Ok(media_files) => media_files, + Err(e) => { + warn!("Query error: {:?}", e); + return Err(ListFeaturedMediaFilesError::ServerError); + } + }; + } + + let response = ListFeaturedMediaFilesSuccessResponse { + success: true, + media_files: media_files.into_iter() + .map(|m| { + let public_bucket_path = MediaFileBucketPath::from_object_hash( + &m.public_bucket_directory_hash, + m.maybe_public_bucket_prefix.as_deref(), + m.maybe_public_bucket_extension.as_deref()) + .get_full_object_path_str() + .to_string(); + + MediaFile { + token: m.token, + media_type: m.media_type, + public_bucket_path, + //origin_category: m.origin_category, + //origin_product_category: m.origin_product_category, + //maybe_origin_model_type: m.maybe_origin_model_type, + //maybe_origin_model_token: m.maybe_origin_model_token, + maybe_creator: UserDetailsLight::from_optional_db_fields_owned( + m.maybe_creator_user_token, + m.maybe_creator_username, + m.maybe_creator_display_name, + m.maybe_creator_email_gravatar_hash + ), + created_at: m.created_at, + updated_at: m.updated_at, + } + }).collect::>(), + }; + + let body = serde_json::to_string(&response) + .map_err(|e| ListFeaturedMediaFilesError::ServerError)?; + + Ok(HttpResponse::Ok() + .content_type("application/json") + .body(body)) +} diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/mod.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/mod.rs index ab3552ac20..2893bf89ce 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/mod.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/mod.rs @@ -1,5 +1,6 @@ pub mod delete_media_file; pub mod drain_multipart_request; pub mod get_media_file; +pub mod list_featured_media_files; pub mod list_media_files; pub mod list_media_files_for_user; diff --git a/crates/service/web/storyteller_web/src/routes.rs b/crates/service/web/storyteller_web/src/routes.rs index 5585ee1370..7e9569dad2 100644 --- a/crates/service/web/storyteller_web/src/routes.rs +++ b/crates/service/web/storyteller_web/src/routes.rs @@ -45,6 +45,7 @@ use crate::http_server::endpoints::investor_demo::enable_demo_mode_handler::enab use crate::http_server::endpoints::leaderboard::get_leaderboard::leaderboard_handler; use crate::http_server::endpoints::media_files::delete_media_file::delete_media_file_handler; use crate::http_server::endpoints::media_files::get_media_file::get_media_file_handler; +use crate::http_server::endpoints::media_files::list_featured_media_files::list_featured_media_files_handler; use crate::http_server::endpoints::media_files::list_media_files::list_media_files_handler; use crate::http_server::endpoints::media_files::list_media_files_for_user::list_media_files_for_user_handler; use crate::http_server::endpoints::media_uploads::list_user_media_uploads_of_type::list_user_media_uploads_of_type_handler; @@ -1024,6 +1025,10 @@ fn add_media_file_routes (app: App) -> App .route(web::get().to(list_media_files_handler)) .route(web::head().to(|| HttpResponse::Ok())) ) + .service(web::resource("/list_featured") + .route(web::get().to(list_featured_media_files_handler)) + .route(web::head().to(|| HttpResponse::Ok())) + ) .service(web::resource("/list/user/{username}") .route(web::get().to(list_media_files_for_user_handler)) .route(web::head().to(|| HttpResponse::Ok())) From 60d419921617164e499e8efa1402216ecdb4e339 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Thu, 14 Dec 2023 16:58:37 -0500 Subject: [PATCH 045/124] fix logout The reason this is so labyrinthine is because of the users and billing components. They bind dynamic behaviors that are defined in storyteller-web (one of them being clearing the redis session cache). Actually, the users component _didn't_, because it was defined in the billing component. So I hoisted it out into a new component library. In the fullness of time I imagine all of this will be consolidated back under storyteller-web so we don't have to worry about binding actions at a distance. Anyway, this is tested and works locally. --- Cargo.lock | 13 +++++++++ Cargo.toml | 1 + crates/service/plugins/billing/Cargo.toml | 1 + ...pe_create_checkout_session_json_handler.rs | 2 +- ...reate_checkout_session_redirect_handler.rs | 2 +- ...te_customer_portal_session_json_handler.rs | 2 +- ...ustomer_portal_session_redirect_handler.rs | 2 +- .../plugins/billing/src/stripe/traits/mod.rs | 1 - .../plugins/user_traits_component/Cargo.toml | 27 +++++++++++++++++++ .../plugins/user_traits_component/src/lib.rs | 21 +++++++++++++++ .../traits/internal_session_cache_purge.rs | 0 .../user_traits_component/src/traits/mod.rs | 1 + crates/service/plugins/users/Cargo.toml | 1 + .../users/src/endpoints/logout_handler.rs | 5 ++++ crates/service/web/storyteller_web/Cargo.toml | 1 + .../internal_session_cache_purge_impl.rs | 2 +- .../service/web/storyteller_web/src/main.rs | 16 +++++------ 17 files changed, 82 insertions(+), 16 deletions(-) create mode 100644 crates/service/plugins/user_traits_component/Cargo.toml create mode 100644 crates/service/plugins/user_traits_component/src/lib.rs rename crates/service/plugins/{billing/src/stripe => user_traits_component/src}/traits/internal_session_cache_purge.rs (100%) create mode 100644 crates/service/plugins/user_traits_component/src/traits/mod.rs diff --git a/Cargo.lock b/Cargo.lock index af9894f874..8d6d76535f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -813,6 +813,7 @@ dependencies = [ "tokio", "toml 0.5.11", "url_config", + "user_traits_component", ] [[package]] @@ -5954,6 +5955,7 @@ dependencies = [ "twitch_oauth2", "url_config", "user_input_common", + "user_traits_component", "users_component", "utoipa", "utoipa-swagger-ui", @@ -7066,6 +7068,16 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "user_traits_component" +version = "0.0.1" +dependencies = [ + "actix-web", + "errors", + "mockall", + "my-workspace-hack", +] + [[package]] name = "users_component" version = "0.0.1" @@ -7109,6 +7121,7 @@ dependencies = [ "tokens", "toml 0.5.11", "user_input_common", + "user_traits_component", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 1ea5d8fefc..411f131e53 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -83,6 +83,7 @@ members = [ # Service Plugins: complete subsystems that can be plugged into services (users, billing, etc.) "crates/service/plugins/billing", "crates/service/plugins/inference_workloads", + "crates/service/plugins/user_traits_component", "crates/service/plugins/users", # Vendored code diff --git a/crates/service/plugins/billing/Cargo.toml b/crates/service/plugins/billing/Cargo.toml index 869eee7790..56a8176786 100644 --- a/crates/service/plugins/billing/Cargo.toml +++ b/crates/service/plugins/billing/Cargo.toml @@ -20,6 +20,7 @@ http_server_common = { path = "../../../lib/deprecated/http_server_common" } mysql_queries = { path = "../../../lib/mysql_queries" } reusable_types = { path = "../../../_types/reusable_types" } url_config = { path = "../../../lib/url_config" } +user_traits_component = { path = "../user_traits_component" } # Workspace hack (faster compile times) my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" } diff --git a/crates/service/plugins/billing/src/stripe/http_endpoints/checkout/create/stripe_create_checkout_session_json_handler.rs b/crates/service/plugins/billing/src/stripe/http_endpoints/checkout/create/stripe_create_checkout_session_json_handler.rs index bdc4de4af8..c81a63b39d 100644 --- a/crates/service/plugins/billing/src/stripe/http_endpoints/checkout/create/stripe_create_checkout_session_json_handler.rs +++ b/crates/service/plugins/billing/src/stripe/http_endpoints/checkout/create/stripe_create_checkout_session_json_handler.rs @@ -3,12 +3,12 @@ use actix_web::web::Json; use reusable_types::server_environment::ServerEnvironment; use url_config::third_party_url_redirector::ThirdPartyUrlRedirector; +use user_traits_component::traits::internal_session_cache_purge::InternalSessionCachePurge; use crate::stripe::http_endpoints::checkout::create::stripe_create_checkout_session_error::CreateCheckoutSessionError; use crate::stripe::http_endpoints::checkout::create::stripe_create_checkout_session_shared::stripe_create_checkout_session_shared; use crate::stripe::stripe_config::StripeConfig; use crate::stripe::traits::internal_product_to_stripe_lookup::InternalProductToStripeLookup; -use crate::stripe::traits::internal_session_cache_purge::InternalSessionCachePurge; use crate::stripe::traits::internal_user_lookup::InternalUserLookup; // =============== Request =============== diff --git a/crates/service/plugins/billing/src/stripe/http_endpoints/checkout/create/stripe_create_checkout_session_redirect_handler.rs b/crates/service/plugins/billing/src/stripe/http_endpoints/checkout/create/stripe_create_checkout_session_redirect_handler.rs index 3f6ccc221d..657761495a 100644 --- a/crates/service/plugins/billing/src/stripe/http_endpoints/checkout/create/stripe_create_checkout_session_redirect_handler.rs +++ b/crates/service/plugins/billing/src/stripe/http_endpoints/checkout/create/stripe_create_checkout_session_redirect_handler.rs @@ -4,12 +4,12 @@ use actix_web::web::Query; use reusable_types::server_environment::ServerEnvironment; use url_config::third_party_url_redirector::ThirdPartyUrlRedirector; +use user_traits_component::traits::internal_session_cache_purge::InternalSessionCachePurge; use crate::stripe::http_endpoints::checkout::create::stripe_create_checkout_session_error::CreateCheckoutSessionError; use crate::stripe::http_endpoints::checkout::create::stripe_create_checkout_session_shared::stripe_create_checkout_session_shared; use crate::stripe::stripe_config::StripeConfig; use crate::stripe::traits::internal_product_to_stripe_lookup::InternalProductToStripeLookup; -use crate::stripe::traits::internal_session_cache_purge::InternalSessionCachePurge; use crate::stripe::traits::internal_user_lookup::InternalUserLookup; // =============== Request =============== diff --git a/crates/service/plugins/billing/src/stripe/http_endpoints/customer_portal/stripe_create_customer_portal_session_json_handler.rs b/crates/service/plugins/billing/src/stripe/http_endpoints/customer_portal/stripe_create_customer_portal_session_json_handler.rs index 3e41b3b2b5..bb21b81621 100644 --- a/crates/service/plugins/billing/src/stripe/http_endpoints/customer_portal/stripe_create_customer_portal_session_json_handler.rs +++ b/crates/service/plugins/billing/src/stripe/http_endpoints/customer_portal/stripe_create_customer_portal_session_json_handler.rs @@ -2,12 +2,12 @@ use actix_web::{HttpRequest, HttpResponse, web}; use actix_web::web::Json; use url_config::third_party_url_redirector::ThirdPartyUrlRedirector; +use user_traits_component::traits::internal_session_cache_purge::InternalSessionCachePurge; use crate::stripe::http_endpoints::customer_portal::stripe_create_customer_portal_session_error::CreateCustomerPortalSessionError; use crate::stripe::http_endpoints::customer_portal::stripe_create_customer_portal_session_shared::stripe_create_customer_portal_session_shared; use crate::stripe::stripe_config::StripeConfig; use crate::stripe::traits::internal_product_to_stripe_lookup::InternalProductToStripeLookup; -use crate::stripe::traits::internal_session_cache_purge::InternalSessionCachePurge; use crate::stripe::traits::internal_user_lookup::InternalUserLookup; // =============== Request =============== diff --git a/crates/service/plugins/billing/src/stripe/http_endpoints/customer_portal/stripe_create_customer_portal_session_redirect_handler.rs b/crates/service/plugins/billing/src/stripe/http_endpoints/customer_portal/stripe_create_customer_portal_session_redirect_handler.rs index c4e69a3288..4aafd6e37c 100644 --- a/crates/service/plugins/billing/src/stripe/http_endpoints/customer_portal/stripe_create_customer_portal_session_redirect_handler.rs +++ b/crates/service/plugins/billing/src/stripe/http_endpoints/customer_portal/stripe_create_customer_portal_session_redirect_handler.rs @@ -3,12 +3,12 @@ use actix_web::{HttpRequest, HttpResponse, web}; use actix_web::web::Query; use url_config::third_party_url_redirector::ThirdPartyUrlRedirector; +use user_traits_component::traits::internal_session_cache_purge::InternalSessionCachePurge; use crate::stripe::http_endpoints::customer_portal::stripe_create_customer_portal_session_error::CreateCustomerPortalSessionError; use crate::stripe::http_endpoints::customer_portal::stripe_create_customer_portal_session_shared::stripe_create_customer_portal_session_shared; use crate::stripe::stripe_config::StripeConfig; use crate::stripe::traits::internal_product_to_stripe_lookup::InternalProductToStripeLookup; -use crate::stripe::traits::internal_session_cache_purge::InternalSessionCachePurge; use crate::stripe::traits::internal_user_lookup::InternalUserLookup; // =============== Request =============== diff --git a/crates/service/plugins/billing/src/stripe/traits/mod.rs b/crates/service/plugins/billing/src/stripe/traits/mod.rs index 2cf3b026fa..44d38b0eac 100644 --- a/crates/service/plugins/billing/src/stripe/traits/mod.rs +++ b/crates/service/plugins/billing/src/stripe/traits/mod.rs @@ -1,4 +1,3 @@ pub mod internal_product_to_stripe_lookup; -pub mod internal_session_cache_purge; pub mod internal_subscription_product_lookup; pub mod internal_user_lookup; \ No newline at end of file diff --git a/crates/service/plugins/user_traits_component/Cargo.toml b/crates/service/plugins/user_traits_component/Cargo.toml new file mode 100644 index 0000000000..6521233d9d --- /dev/null +++ b/crates/service/plugins/user_traits_component/Cargo.toml @@ -0,0 +1,27 @@ +[package] +publish = false +name = "user_traits_component" +edition = "2018" +version = "0.0.1" +authors = [ + "Brandon Thomas ", + "Brandon Thomas ", +] + +[lib] +name = "user_traits_component" +path = "src/lib.rs" + +[dependencies] + +# Internal +errors = { path = "../../../lib/errors" } + +# Workspace hack (faster compile times) +my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" } + +# Web +actix-web = "4.4.0" + +[dev-dependencies] +mockall = "0.11.3" diff --git a/crates/service/plugins/user_traits_component/src/lib.rs b/crates/service/plugins/user_traits_component/src/lib.rs new file mode 100644 index 0000000000..a490ebd661 --- /dev/null +++ b/crates/service/plugins/user_traits_component/src/lib.rs @@ -0,0 +1,21 @@ +//! user_traits_component +//! +//! Expose some traits for other plugins / components. +//! This will probably go away once we start consolidating the plugins into the main service. +//! + +// Never allow these +#![forbid(private_in_public)] +#![forbid(unused_must_use)] // NB: It's unsafe to not close/check some things + +// Okay to toggle +#![forbid(unreachable_patterns)] +#![forbid(unused_imports)] +#![forbid(unused_mut)] +#![forbid(unused_variables)] + +// Always allow +#![allow(dead_code)] +#![allow(non_snake_case)] + +pub mod traits; diff --git a/crates/service/plugins/billing/src/stripe/traits/internal_session_cache_purge.rs b/crates/service/plugins/user_traits_component/src/traits/internal_session_cache_purge.rs similarity index 100% rename from crates/service/plugins/billing/src/stripe/traits/internal_session_cache_purge.rs rename to crates/service/plugins/user_traits_component/src/traits/internal_session_cache_purge.rs diff --git a/crates/service/plugins/user_traits_component/src/traits/mod.rs b/crates/service/plugins/user_traits_component/src/traits/mod.rs new file mode 100644 index 0000000000..01df49e0ee --- /dev/null +++ b/crates/service/plugins/user_traits_component/src/traits/mod.rs @@ -0,0 +1 @@ +pub mod internal_session_cache_purge; diff --git a/crates/service/plugins/users/Cargo.toml b/crates/service/plugins/users/Cargo.toml index 86db221476..7d2a8f616e 100644 --- a/crates/service/plugins/users/Cargo.toml +++ b/crates/service/plugins/users/Cargo.toml @@ -30,6 +30,7 @@ reusable_types = { path = "../../../_types/reusable_types" } server_environment = { path = "../../../lib/server_environment" } tokens = { path = "../../../_types/tokens" } user_input_common = { path = "../../../lib/user_input_common" } +user_traits_component = { path = "../user_traits_component" } # Workspace hack (faster compile times) my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" } diff --git a/crates/service/plugins/users/src/endpoints/logout_handler.rs b/crates/service/plugins/users/src/endpoints/logout_handler.rs index 806b525d48..4c51375357 100644 --- a/crates/service/plugins/users/src/endpoints/logout_handler.rs +++ b/crates/service/plugins/users/src/endpoints/logout_handler.rs @@ -13,6 +13,7 @@ use sqlx::MySqlPool; use http_server_common::response::response_error_helpers::to_simple_json_error; use mysql_queries::queries::users::user_sessions::delete_user_session::delete_user_session; +use user_traits_component::traits::internal_session_cache_purge::InternalSessionCachePurge; use crate::cookies::session::session_cookie_manager::SessionCookieManager; @@ -53,8 +54,12 @@ pub async fn logout_handler( http_request: HttpRequest, session_cookie_manager: web::Data, mysql_pool: web::Data, + internal_session_cache_purge: web::Data, ) -> Result { + // Best effort to delete Redis session cache + internal_session_cache_purge.best_effort_purge_session_cache(&http_request); + let mut delete_cookie = match http_request.cookie("session") { Some(cookie) => { match session_cookie_manager.decode_session_token(&cookie) { diff --git a/crates/service/web/storyteller_web/Cargo.toml b/crates/service/web/storyteller_web/Cargo.toml index bc0e4b61bc..6767b33240 100644 --- a/crates/service/web/storyteller_web/Cargo.toml +++ b/crates/service/web/storyteller_web/Cargo.toml @@ -52,6 +52,7 @@ user_input_common = { path = "../../../lib/user_input_common" } # Internal Components billing_component = { path = "../../plugins/billing" } +user_traits_component = { path = "../../plugins/user_traits_component" } users_component = { path = "../../plugins/users" } # Workspace hack (faster compile times) diff --git a/crates/service/web/storyteller_web/src/billing/internal_session_cache_purge_impl.rs b/crates/service/web/storyteller_web/src/billing/internal_session_cache_purge_impl.rs index c296ed5296..2dcf6eb523 100644 --- a/crates/service/web/storyteller_web/src/billing/internal_session_cache_purge_impl.rs +++ b/crates/service/web/storyteller_web/src/billing/internal_session_cache_purge_impl.rs @@ -1,8 +1,8 @@ use actix_web::HttpRequest; -use billing_component::stripe::traits::internal_session_cache_purge::InternalSessionCachePurge; use redis_caching::redis_ttl_cache::RedisTtlCache; use redis_common::redis_cache_keys::RedisCacheKeys; +use user_traits_component::traits::internal_session_cache_purge::InternalSessionCachePurge; use users_component::utils::session_checker::SessionChecker; pub struct InternalSessionCachePurgeImpl { diff --git a/crates/service/web/storyteller_web/src/main.rs b/crates/service/web/storyteller_web/src/main.rs index 57f09a82c8..8b815cd6f3 100644 --- a/crates/service/web/storyteller_web/src/main.rs +++ b/crates/service/web/storyteller_web/src/main.rs @@ -20,15 +20,13 @@ use std::sync::Arc; use std::time::Duration; -use actix_cors::Cors; -use actix_web::{App, HttpResponse, HttpServer, middleware, web}; +use actix_web::{App, HttpServer, middleware, web}; use actix_web::middleware::{DefaultHeaders, Logger}; use anyhow::anyhow; use elasticsearch::Elasticsearch; use elasticsearch::http::transport::Transport; use futures::Future; -use limitation::Limiter; -use log::{error, info}; +use log::info; use r2d2_redis::r2d2; use r2d2_redis::redis::Commands; use r2d2_redis::RedisConnectionManager; @@ -48,7 +46,6 @@ use actix_helpers::middleware::disabled_endpoint_filter::disabled_endpoints::exa use actix_helpers::middleware::disabled_endpoint_filter::disabled_endpoints::prefix_disabled_endpoints::PrefixDisabledEndpoints; use billing_component::stripe::stripe_config::{FullUrlOrPath, StripeCheckoutConfigs, StripeConfig, StripeCustomerPortalConfigs, StripeSecrets}; use billing_component::stripe::traits::internal_product_to_stripe_lookup::InternalProductToStripeLookup; -use billing_component::stripe::traits::internal_session_cache_purge::InternalSessionCachePurge; use billing_component::stripe::traits::internal_subscription_product_lookup::InternalSubscriptionProductLookup; use billing_component::stripe::traits::internal_user_lookup::InternalUserLookup; use bootstrap::bootstrap::{bootstrap, BootstrapArgs}; @@ -56,10 +53,9 @@ use cloud_storage::bucket_client::BucketClient; use config::common_env::CommonEnv; use config::shared_constants::DEFAULT_MYSQL_CONNECTION_STRING; use config::shared_constants::DEFAULT_RUST_LOG; -use container_common::files::read_toml_file_to_struct::read_toml_file_to_struct; use email_sender::smtp_email_sender::SmtpEmailSender; use errors::AnyhowResult; -use http_server_common::cors::{build_cors_config, build_production_cors_config}; +use http_server_common::cors::build_cors_config; use memory_caching::single_item_ttl_cache::SingleItemTtlCache; use mysql_queries::mediators::badge_granter::BadgeGranter; use mysql_queries::mediators::firehose_publisher::FirehosePublisher; @@ -67,6 +63,7 @@ use redis_caching::redis_ttl_cache::RedisTtlCache; use reusable_types::server_environment::ServerEnvironment; use twitch_common::twitch_secrets::TwitchSecrets; use url_config::third_party_url_redirector::ThirdPartyUrlRedirector; +use user_traits_component::traits::internal_session_cache_purge::InternalSessionCachePurge; use users_component::cookies::anonymous_visitor_tracking::avt_cookie_manager::AvtCookieManager; use users_component::cookies::session::session_cookie_manager::SessionCookieManager; use users_component::utils::session_checker::SessionChecker; @@ -76,12 +73,11 @@ use crate::billing::internal_session_cache_purge_impl::InternalSessionCachePurge use crate::billing::stripe_internal_subscription_product_lookup_impl::StripeInternalSubscriptionProductLookupImpl; use crate::billing::stripe_internal_user_lookup_impl::StripeInternalUserLookupImpl; use crate::configs::app_startup::redis_rate_limiters::configure_redis_rate_limiters; -use crate::configs::static_api_tokens::{StaticApiTokenConfig, StaticApiTokens, StaticApiTokenSet}; +use crate::configs::static_api_tokens::StaticApiTokenSet; use crate::http_server::middleware::pushback_filter_middleware::PushbackFilter; -use crate::http_server::web_utils::redis_rate_limiter::RedisRateLimiter; use crate::memory_cache::model_token_to_info_cache::ModelTokenToInfoCache; use crate::routes::add_routes; -use crate::server_state::{DurableInMemoryCaches, EnvConfig, EphemeralInMemoryCaches, InMemoryCaches, RedisRateLimiters, ServerInfo, ServerState, StaticFeatureFlags, StripeSettings, TrollBans, TwitchOauth, TwitchOauthSecrets}; +use crate::server_state::{DurableInMemoryCaches, EnvConfig, EphemeralInMemoryCaches, InMemoryCaches, ServerInfo, ServerState, StaticFeatureFlags, StripeSettings, TrollBans, TwitchOauth, TwitchOauthSecrets}; use crate::threads::db_health_checker_thread::db_health_check_status::HealthCheckStatus; use crate::threads::db_health_checker_thread::db_health_checker_thread::db_health_checker_thread; use crate::threads::poll_ip_banlist_thread::poll_ip_bans; From e9cd505e0bbe5a2c6a547e0fc75d84f3ec026f5c Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Thu, 14 Dec 2023 18:11:34 -0500 Subject: [PATCH 046/124] Fix clap in various CLI tools post 2.x -> 4.x upgrade --- Cargo.lock | 2 - crates/cli/dev_database_seed/Cargo.toml | 2 +- crates/cli/dev_database_seed/src/cli_args.rs | 25 +++----- crates/cli/dev_upload_media_file/Cargo.toml | 2 +- .../cli/dev_upload_media_file/src/cli_args.rs | 29 ++++----- crates/cli/elasticsearch-cli/Cargo.toml | 2 +- crates/cli/elasticsearch-cli/src/cli_args.rs | 63 +++++++------------ crates/cli/scrape_test/Cargo.toml | 2 +- crates/cli/scrape_test/src/main.rs | 34 +++++----- .../service/job/email_sender_job/Cargo.toml | 1 - .../service/job/tts_inference_job/Cargo.toml | 1 - .../service/job/tts_inference_job/src/main.rs | 16 +---- 12 files changed, 63 insertions(+), 116 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cc0a9d9644..7af174d2be 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2068,7 +2068,6 @@ dependencies = [ "bootstrap", "buckets", "chrono", - "clap", "cloud_storage", "concurrency", "config", @@ -6707,7 +6706,6 @@ version = "0.0.1" dependencies = [ "anyhow", "chrono", - "clap", "cloud_storage", "collections", "config", diff --git a/crates/cli/dev_database_seed/Cargo.toml b/crates/cli/dev_database_seed/Cargo.toml index b065225a7f..26c93882f5 100644 --- a/crates/cli/dev_database_seed/Cargo.toml +++ b/crates/cli/dev_database_seed/Cargo.toml @@ -33,7 +33,7 @@ my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" } # External log = "0.4.14" -clap = "4.4.8" # TODO: This is really out of date, but has conflicts when updated +clap = "4.4.8" rand = "0.8.5" # Runtime # NB: We switched to Tokio from `async-std` for broader ecosystem support. diff --git a/crates/cli/dev_database_seed/src/cli_args.rs b/crates/cli/dev_database_seed/src/cli_args.rs index 6fb2e244c4..6642fe625e 100644 --- a/crates/cli/dev_database_seed/src/cli_args.rs +++ b/crates/cli/dev_database_seed/src/cli_args.rs @@ -1,28 +1,17 @@ -use clap::{App, Arg}; +use clap::Parser; use errors::AnyhowResult; +#[derive(Parser, Debug)] +#[command(name="dev-database-seed")] pub struct CliArgs { + #[arg(name="seed_cloud_bucket", long="bucket", help="Seed the cloud bucket with files", required=false, default_value_t=false)] pub seed_cloud_bucket: bool, + + #[arg(name="seed_elasticsearch", long="elasticsearch", help="Seed the local elasticsearch", required=false, default_value_t=false)] pub seed_elasticsearch: bool, } pub fn parse_cli_args() -> AnyhowResult { - let matches = App::new("dev-database-seed") - .arg(Arg::with_name("seed_cloud_bucket") - .long("bucket") - .help("Seed the cloud bucket with files") - .takes_value(false) - .required(false)) - .arg(Arg::with_name("seed_elasticsearch") - .long("elasticsearch") - .help("Seed the local elasticsearch") - .takes_value(false) - .required(false)) - .get_matches(); - - Ok(CliArgs { - seed_cloud_bucket: matches.is_present("seed_cloud_bucket"), - seed_elasticsearch: matches.is_present("seed_elasticsearch"), - }) + Ok(CliArgs::parse()) } diff --git a/crates/cli/dev_upload_media_file/Cargo.toml b/crates/cli/dev_upload_media_file/Cargo.toml index 9d928ea9e1..ad35f9d3b9 100644 --- a/crates/cli/dev_upload_media_file/Cargo.toml +++ b/crates/cli/dev_upload_media_file/Cargo.toml @@ -29,7 +29,7 @@ tokens = { path = "../../_types/tokens" } my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" } # External -clap = "4.4.8" # TODO: This is really out of date, but has conflicts when updated +clap = "4.4.8" log = "0.4.14" # Runtime diff --git a/crates/cli/dev_upload_media_file/src/cli_args.rs b/crates/cli/dev_upload_media_file/src/cli_args.rs index 1cf2ca590f..32ad7a5f4c 100644 --- a/crates/cli/dev_upload_media_file/src/cli_args.rs +++ b/crates/cli/dev_upload_media_file/src/cli_args.rs @@ -1,27 +1,24 @@ use std::path::PathBuf; -use clap::{App, Arg}; -use errors::{anyhow, AnyhowResult}; + +use clap::Parser; + +use errors::AnyhowResult; + +#[derive(Parser, Debug)] +#[command(name="dev-upload-media-file")] +pub struct RawArgs { + #[arg(name="file", short='f', long="file", help="File to upload", required=true)] + pub file_path: String, +} pub struct CliArgs { pub file_path: PathBuf, } pub fn parse_cli_args() -> AnyhowResult { - let matches = App::new("dev_upload_media") - .arg(Arg::with_name("file") - .short("f") - .long("file") - .value_name("FILE") - .help("File to upload") - .takes_value(true) - .required(true)) - .get_matches(); - - let file_path = matches.value_of("file") - .map(|val| val.trim().to_string()) - .ok_or(anyhow!("no file path supplied"))?; + let args = RawArgs::parse(); Ok(CliArgs { - file_path: PathBuf::from(file_path), + file_path: PathBuf::from(args.file_path), }) } diff --git a/crates/cli/elasticsearch-cli/Cargo.toml b/crates/cli/elasticsearch-cli/Cargo.toml index 9b0af1cde7..6921e54cda 100644 --- a/crates/cli/elasticsearch-cli/Cargo.toml +++ b/crates/cli/elasticsearch-cli/Cargo.toml @@ -29,7 +29,7 @@ my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" } # External log = "0.4.14" -clap = "4.4.8" # TODO: This is really out of date, but has conflicts when updated +clap = "4.4.8" strum = { version = "0.25", features = ["derive"] } # Runtime diff --git a/crates/cli/elasticsearch-cli/src/cli_args.rs b/crates/cli/elasticsearch-cli/src/cli_args.rs index 5c2c7e1a41..9b7a25e815 100644 --- a/crates/cli/elasticsearch-cli/src/cli_args.rs +++ b/crates/cli/elasticsearch-cli/src/cli_args.rs @@ -1,12 +1,12 @@ use std::str::FromStr; -use clap::{App, Arg, ArgMatches}; +use clap::Parser; use strum::{EnumCount, EnumString, IntoEnumIterator}; use strum::EnumIter; use errors::{anyhow, AnyhowResult, bail}; -pub struct CliArgs { +pub struct ParsedArgs { pub mysql_environment: Environment, pub elasticsearch_environment: Environment, pub action: Action, @@ -25,53 +25,38 @@ pub enum Action { SearchTts, } -pub fn parse_cli_args() -> AnyhowResult { - let matches = App::new("dev-database-seed") - .arg(Arg::with_name("action") - .long("action") - .help("action to take") - .takes_value(true) - .required(true)) - .arg(Arg::with_name("mysql") - .long("mysql") - .help("Production or development") - .takes_value(true) - .required(false)) - .arg(Arg::with_name("elasticsearch") - .long("elasticsearch") - .help("Production or development") - .takes_value(true) - .required(false)) - .get_matches(); +#[derive(Parser, Debug)] +#[command(name="elasticsearch-cli")] +pub struct Args { + #[arg(name="action", long="action", help="action to take", required=true)] + action: String, - Ok(CliArgs { - mysql_environment: to_environment(&matches, "mysql")?, - elasticsearch_environment: to_environment(&matches, "elasticsearch")?, - action: get_action(&matches)?, + #[arg(name="mysql", long="mysql", help="production or development")] + mysql: Option, + + #[arg(name="elasticsearch", long="elasticsearch", help="production or development")] + elasticsearch: Option, +} + +pub fn parse_cli_args() -> AnyhowResult { + let args = Args::parse(); + + Ok(ParsedArgs { + mysql_environment: to_environment(args.mysql.as_deref())?, + elasticsearch_environment: to_environment(args.elasticsearch.as_deref())?, + action: action_from_str(&args.action)?, }) } -fn to_environment(matches: &ArgMatches, key: &str) -> AnyhowResult { - let value = matches.value_of(key) - .map(|s| s.to_lowercase()); - - Ok(match value.as_deref() { +fn to_environment(environment: Option<&str>) -> AnyhowResult { + Ok(match environment { None => Environment::Development, Some("dev") | Some("development") => Environment::Development, Some("prod") | Some("production") => Environment::Production, - _ => bail!("invalid environment: {:?}", value), + _ => bail!("invalid environment: {:?}", environment), }) } -fn get_action(matches: &ArgMatches) -> AnyhowResult { - let action = matches.value_of("action") - .map(|s| action_from_str(s)) - .transpose()? - .ok_or(anyhow!("no action provided"))?; - - Ok(action) -} - fn action_from_str(value: &str) -> AnyhowResult { let action = Action::from_str(value) .map_err(|err| { diff --git a/crates/cli/scrape_test/Cargo.toml b/crates/cli/scrape_test/Cargo.toml index f68f20dc30..64dfd5adb6 100644 --- a/crates/cli/scrape_test/Cargo.toml +++ b/crates/cli/scrape_test/Cargo.toml @@ -22,5 +22,5 @@ web_scrapers = { path = "../../lib/web_scrapers" } my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" } # External -clap = "4.4.8" # TODO: This is really out of date, but has conflicts when updated +clap = "4.4.8" tokio = { version = "1.34.0", features = ["macros"] } diff --git a/crates/cli/scrape_test/src/main.rs b/crates/cli/scrape_test/src/main.rs index 71abbd5d11..42d3c8a51a 100644 --- a/crates/cli/scrape_test/src/main.rs +++ b/crates/cli/scrape_test/src/main.rs @@ -1,30 +1,24 @@ -use clap::{App, Arg}; +use clap::Parser; use errors::{anyhow, AnyhowResult}; use web_scrapers::scrape_supported_webpage::scrape_supported_webpage; +#[derive(Parser, Debug)] +#[command(name = "scrape_test")] +pub struct Args { + #[arg(name="url", short='u', long = "url", help = "URL of the page to scrape", required = true)] + url: String, + + #[arg(name="print_html", long = "html", help = "Print the HTML scraped", required = true)] + print_html: bool, +} + #[tokio::main] pub async fn main() -> AnyhowResult<()> { - let matches = App::new("scrape_test") - .arg(Arg::with_name("url") - .short("u") - .long("url") - .value_name("URL") - .help("URL of the page to scrape") - .takes_value(true) - .required(true)) - .arg(Arg::with_name("print_html") - .long("html") - .help("Print the HTML scraped") - .takes_value(false) - .required(false)) - .get_matches(); + let args = Args::parse(); - let url = matches.value_of("url") - .map(|val| val.trim().to_string()) - .ok_or(anyhow!("no url supplied"))?; - - let print_html = matches.is_present("print_html"); + let url = args.url.trim().to_string(); + let print_html = args.print_html; let scrape_result = scrape_supported_webpage(&url).await?; diff --git a/crates/service/job/email_sender_job/Cargo.toml b/crates/service/job/email_sender_job/Cargo.toml index 07db875a2e..7fd93708f7 100644 --- a/crates/service/job/email_sender_job/Cargo.toml +++ b/crates/service/job/email_sender_job/Cargo.toml @@ -47,7 +47,6 @@ my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" } # External anyhow = "1.0.75" chrono = { version = "0.4.22", features = ["serde"] } -clap = "4.4.8" # TODO: This is really out of date, but has conflicts when updated dotenv = "0.15.0" hostname = "0.3.1" lfu = "0.2.5" diff --git a/crates/service/job/tts_inference_job/Cargo.toml b/crates/service/job/tts_inference_job/Cargo.toml index 02b6a01ed5..3695ed9a29 100644 --- a/crates/service/job/tts_inference_job/Cargo.toml +++ b/crates/service/job/tts_inference_job/Cargo.toml @@ -33,7 +33,6 @@ my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" } # External anyhow = "1.0.75" chrono = { version = "0.4.22", features = ["serde"] } -clap = "4.4.8" # TODO: This is really out of date, but has conflicts when updated dotenv = "0.15.0" hostname = "0.3.1" lfu = "0.2.5" diff --git a/crates/service/job/tts_inference_job/src/main.rs b/crates/service/job/tts_inference_job/src/main.rs index db471482ac..18b2dc41cf 100644 --- a/crates/service/job/tts_inference_job/src/main.rs +++ b/crates/service/job/tts_inference_job/src/main.rs @@ -18,7 +18,6 @@ use std::path::PathBuf; use std::time::Duration; -use clap::{App, Arg}; use log::{error, info, warn}; use r2d2_redis::r2d2; use r2d2_redis::RedisConnectionManager; @@ -93,15 +92,6 @@ async fn main() -> AnyhowResult<()> { // This file should only contain *development* secrets, never production. let _ = dotenv::from_filename(".env-secrets").ok(); - let matches = App::new("tts-inference-job") - .arg(Arg::with_name("sidecar_hostname") - .long("sidecar_hostname") - .value_name("HOSTNAME") - .help("Hostname for the TTS inference sidecar") - .takes_value(true) - .required(false)) - .get_matches(); - info!("Obtaining worker hostname..."); let server_hostname = hostname::get() @@ -150,13 +140,9 @@ async fn main() -> AnyhowResult<()> { Some(bucket_timeout), )?; - let mut sidecar_hostname = + let sidecar_hostname = easyenv::get_env_string_required(ENV_TTS_INFERENCE_SIDECAR_HOSTNAME)?; - if let Some(hostname) = matches.value_of("sidecar_hostname") { - sidecar_hostname = hostname.to_string(); - } - info!("Sidecar hostname: {:?}", sidecar_hostname); let tts_inference_sidecar_client = From 6c9b0a5c2abe241ce336b52928be5302b2eaef3e Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Thu, 14 Dec 2023 18:30:54 -0500 Subject: [PATCH 047/124] fix bad github merge --- .../http_server/endpoints/media_files/mod.rs | 3 +-- .../service/web/storyteller_web/src/routes.rs | 19 +++++++++---------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/mod.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/mod.rs index 1883621d7a..8365645e1f 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/mod.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/mod.rs @@ -1,8 +1,7 @@ pub mod delete_media_file; pub mod drain_multipart_request; pub mod get_media_file; -pub mod delete_media_file; -pub mod update_media_file; pub mod list_featured_media_files; pub mod list_media_files; pub mod list_media_files_for_user; +pub mod update_media_file; diff --git a/crates/service/web/storyteller_web/src/routes.rs b/crates/service/web/storyteller_web/src/routes.rs index 79c10e153a..aafc1d1442 100644 --- a/crates/service/web/storyteller_web/src/routes.rs +++ b/crates/service/web/storyteller_web/src/routes.rs @@ -29,11 +29,6 @@ use crate::http_server::endpoints::comments::list_comments_handler::list_comment use crate::http_server::endpoints::download_job::enqueue_generic_download::enqueue_generic_download_handler; use crate::http_server::endpoints::download_job::get_generic_upload_job_status::get_generic_download_job_status_handler; use crate::http_server::endpoints::events::list_events::list_events_handler; -use crate::http_server::endpoints::user_bookmarks::create_user_bookmark_handler::create_user_bookmark_handler; -use crate::http_server::endpoints::user_bookmarks::delete_user_bookmark_handler::delete_user_bookmark_handler; -use crate::http_server::endpoints::user_bookmarks::list_user_bookmarks_for_entity_handler::list_user_bookmarks_for_entity_handler; -use crate::http_server::endpoints::user_bookmarks::list_user_bookmarks_for_session_handler::list_user_bookmarks_for_session_handler; -use crate::http_server::endpoints::user_bookmarks::list_user_bookmarks_for_user_handler::list_user_bookmarks_for_user_handler; use crate::http_server::endpoints::flags::design_refresh_flag::disable_design_refresh_flag_handler::disable_design_refresh_flag_handler; use crate::http_server::endpoints::flags::design_refresh_flag::enable_design_refresh_flag_handler::enable_design_refresh_flag_handler; use crate::http_server::endpoints::inference_job::get_inference_job_status::get_inference_job_status_handler; @@ -45,10 +40,10 @@ use crate::http_server::endpoints::investor_demo::enable_demo_mode_handler::enab use crate::http_server::endpoints::leaderboard::get_leaderboard::leaderboard_handler; use crate::http_server::endpoints::media_files::delete_media_file::delete_media_file_handler; use crate::http_server::endpoints::media_files::get_media_file::get_media_file_handler; -use crate::http_server::endpoints::media_files::update_media_file::update_media_file_handler; use crate::http_server::endpoints::media_files::list_featured_media_files::list_featured_media_files_handler; use crate::http_server::endpoints::media_files::list_media_files::list_media_files_handler; use crate::http_server::endpoints::media_files::list_media_files_for_user::list_media_files_for_user_handler; +use crate::http_server::endpoints::media_files::update_media_file::update_media_file_handler; use crate::http_server::endpoints::media_uploads::list_user_media_uploads_of_type::list_user_media_uploads_of_type_handler; use crate::http_server::endpoints::media_uploads::upload_audio::upload_audio_handler; use crate::http_server::endpoints::media_uploads::upload_image::upload_image_handler; @@ -112,6 +107,11 @@ use crate::http_server::endpoints::twitch::oauth::check_oauth_status::check_oaut use crate::http_server::endpoints::twitch::oauth::oauth_begin_json::oauth_begin_enroll_json; use crate::http_server::endpoints::twitch::oauth::oauth_begin_redirect::oauth_begin_enroll_redirect; use crate::http_server::endpoints::twitch::oauth::oauth_end::oauth_end_enroll_from_redirect; +use crate::http_server::endpoints::user_bookmarks::create_user_bookmark_handler::create_user_bookmark_handler; +use crate::http_server::endpoints::user_bookmarks::delete_user_bookmark_handler::delete_user_bookmark_handler; +use crate::http_server::endpoints::user_bookmarks::list_user_bookmarks_for_entity_handler::list_user_bookmarks_for_entity_handler; +use crate::http_server::endpoints::user_bookmarks::list_user_bookmarks_for_session_handler::list_user_bookmarks_for_session_handler; +use crate::http_server::endpoints::user_bookmarks::list_user_bookmarks_for_user_handler::list_user_bookmarks_for_user_handler; use crate::http_server::endpoints::user_ratings::get_user_rating_handler::get_user_rating_handler; use crate::http_server::endpoints::user_ratings::set_user_rating_handler::set_user_rating_handler; use crate::http_server::endpoints::vocoders::get_vocoder::get_vocoder_handler; @@ -154,14 +154,12 @@ use crate::http_server::endpoints::w2l::list_user_w2l_inference_results::list_us use crate::http_server::endpoints::w2l::list_user_w2l_templates::list_user_w2l_templates_handler; use crate::http_server::endpoints::w2l::list_w2l_templates::list_w2l_templates_handler; use crate::http_server::endpoints::w2l::set_w2l_template_mod_approval::set_w2l_template_mod_approval_handler; - -use crate::http_server::endpoints::weights::get_weight::get_weight_handler; use crate::http_server::endpoints::weights::delete_weight::delete_weight_handler; -use crate::http_server::endpoints::weights::update_weight::update_weight_handler; +use crate::http_server::endpoints::weights::get_weight::get_weight_handler; use crate::http_server::endpoints::weights::list_available_weights::list_available_weights_handler; use crate::http_server::endpoints::weights::list_featured_weights::list_featured_weights_handler; use crate::http_server::endpoints::weights::list_weights_by_user::list_weights_by_user_handler; - +use crate::http_server::endpoints::weights::update_weight::update_weight_handler; pub fn add_routes (app: App, server_environment: ServerEnvironment) -> App where @@ -1024,6 +1022,7 @@ fn add_media_file_routes (app: App) -> App ) .service(web::resource("/file/{token}/update") .route(web::post().to(update_media_file_handler)) + ) .service(web::resource("/list") .route(web::get().to(list_media_files_handler)) .route(web::head().to(|| HttpResponse::Ok())) From 186979ecbdbe432b86f64362b27d8f8f075d7d02 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Thu, 14 Dec 2023 18:40:44 -0500 Subject: [PATCH 048/124] fix lints and other issues --- .../src/seeding/seed_model_weights.rs | 12 ++++++------ crates/cli/scrape_test/src/main.rs | 2 +- .../queries/media_files/list_media_files_for_user.rs | 5 +---- .../job_types/videofilter/process_single_vf_job.rs | 7 ------- .../service/plugins/user_traits_component/src/lib.rs | 2 +- 5 files changed, 9 insertions(+), 19 deletions(-) diff --git a/crates/cli/dev_database_seed/src/seeding/seed_model_weights.rs b/crates/cli/dev_database_seed/src/seeding/seed_model_weights.rs index ac6388b877..e3e025f855 100644 --- a/crates/cli/dev_database_seed/src/seeding/seed_model_weights.rs +++ b/crates/cli/dev_database_seed/src/seeding/seed_model_weights.rs @@ -123,8 +123,8 @@ pub async fn seed_weights_files( let create_model_weights_args = CreateModelWeightsArgs { token: &model_weight_token, - weights_type: weights_type, // Assuming weights_type is defined elsewhere - weights_category: weights_category, // Assuming weights_category is defined elsewhere + weights_type, // Assuming weights_type is defined elsewhere + weights_category, // Assuming weights_category is defined elsewhere title: title.to_string(), maybe_thumbnail_token: Some(thumbnail_token), description_markdown: description.to_string(), @@ -140,11 +140,11 @@ pub async fn seed_weights_files( private_bucket_hash: public_bucket_hash, maybe_private_bucket_prefix: Some(public_bucket_prefix.to_string()), maybe_private_bucket_extension: Some(public_bucket_extension.to_string()), - cached_user_ratings_total_count: cached_user_ratings_total_count, - cached_user_ratings_positive_count: cached_user_ratings_positive_count, - cached_user_ratings_negative_count: cached_user_ratings_negative_count, + cached_user_ratings_total_count, + cached_user_ratings_positive_count, + cached_user_ratings_negative_count, maybe_cached_user_ratings_ratio: Some(cached_user_ratings_ratio), - version: version, + version, mysql_pool: &mysql_pool, // Assuming mysql_pool is defined elsewhere }; diff --git a/crates/cli/scrape_test/src/main.rs b/crates/cli/scrape_test/src/main.rs index 42d3c8a51a..4053e22a89 100644 --- a/crates/cli/scrape_test/src/main.rs +++ b/crates/cli/scrape_test/src/main.rs @@ -1,6 +1,6 @@ use clap::Parser; -use errors::{anyhow, AnyhowResult}; +use errors::AnyhowResult; use web_scrapers::scrape_supported_webpage::scrape_supported_webpage; #[derive(Parser, Debug)] diff --git a/crates/lib/mysql_queries/src/queries/media_files/list_media_files_for_user.rs b/crates/lib/mysql_queries/src/queries/media_files/list_media_files_for_user.rs index d7115cd5a6..c8f32280d8 100644 --- a/crates/lib/mysql_queries/src/queries/media_files/list_media_files_for_user.rs +++ b/crates/lib/mysql_queries/src/queries/media_files/list_media_files_for_user.rs @@ -1,5 +1,4 @@ use chrono::{DateTime, Utc}; -use log::warn; use sqlx::{FromRow, MySql, MySqlPool, QueryBuilder, Row}; use sqlx::mysql::MySqlRow; @@ -12,8 +11,6 @@ use enums::traits::mysql_from_row::MySqlFromRow; use errors::AnyhowResult; use tokens::tokens::media_files::MediaFileToken; - - pub struct MediaFileListPage { pub records: Vec, @@ -210,7 +207,7 @@ WHERE m.user_deleted_at IS NULL query_builder.push(" ORDER BY m.id DESC "); } - if (enforce_limits) { + if enforce_limits { if cursor_is_reversed { query_builder.push(format!(" LIMIT {limit_start}, {limit_end} ")); } else { diff --git a/crates/service/job/inference_job/src/job/job_types/videofilter/process_single_vf_job.rs b/crates/service/job/inference_job/src/job/job_types/videofilter/process_single_vf_job.rs index 9d7cc0163c..d5ab7b371c 100644 --- a/crates/service/job/inference_job/src/job/job_types/videofilter/process_single_vf_job.rs +++ b/crates/service/job/inference_job/src/job/job_types/videofilter/process_single_vf_job.rs @@ -1,11 +1,4 @@ -use anyhow::anyhow; -use log::info; - -use mysql_queries::payloads::generic_inference_args::generic_inference_args::PolymorphicInferenceArgs::Rr; -use mysql_queries::payloads::generic_inference_args::videofilter_payload::VideofilterVideoSource; use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob; -use mysql_queries::queries::media_files::get_media_file::get_media_file; -use tokens::tokens::media_files::MediaFileToken; use crate::job::job_loop::job_success_result::JobSuccessResult; use crate::job::job_loop::process_single_job_error::ProcessSingleJobError; diff --git a/crates/service/plugins/user_traits_component/src/lib.rs b/crates/service/plugins/user_traits_component/src/lib.rs index a490ebd661..e3e74a585d 100644 --- a/crates/service/plugins/user_traits_component/src/lib.rs +++ b/crates/service/plugins/user_traits_component/src/lib.rs @@ -12,7 +12,7 @@ #![forbid(unreachable_patterns)] #![forbid(unused_imports)] #![forbid(unused_mut)] -#![forbid(unused_variables)] +#![allow(unused_variables)] // NB: issue with automock // Always allow #![allow(dead_code)] From 6fc1dd263c1b9d0c96cfcba52fd725df50e26743 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Thu, 14 Dec 2023 20:23:03 -0500 Subject: [PATCH 049/124] migration dir had a space in it --- .../down.sql | 0 .../up.sql | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename _sql/migrations/{2023-12-11-115710_add user_bookmarks => 2023-12-11-115710_add_user_bookmarks}/down.sql (100%) rename _sql/migrations/{2023-12-11-115710_add user_bookmarks => 2023-12-11-115710_add_user_bookmarks}/up.sql (100%) diff --git a/_sql/migrations/2023-12-11-115710_add user_bookmarks/down.sql b/_sql/migrations/2023-12-11-115710_add_user_bookmarks/down.sql similarity index 100% rename from _sql/migrations/2023-12-11-115710_add user_bookmarks/down.sql rename to _sql/migrations/2023-12-11-115710_add_user_bookmarks/down.sql diff --git a/_sql/migrations/2023-12-11-115710_add user_bookmarks/up.sql b/_sql/migrations/2023-12-11-115710_add_user_bookmarks/up.sql similarity index 100% rename from _sql/migrations/2023-12-11-115710_add user_bookmarks/up.sql rename to _sql/migrations/2023-12-11-115710_add_user_bookmarks/up.sql From 5108f94c0f33ca53dd6f4d3b34f7094345505069 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Thu, 14 Dec 2023 21:45:44 -0500 Subject: [PATCH 050/124] Lots of schema changes afoot - model_weights migration, covers, samples Model weights migration (old tokens): - model_weights.maybe_migration_old_model_token Model weights migration (new tokens): - tts_models.maybe_migration_new_model_weights_token - vocoder_models.maybe_migration_new_model_weights_token - voice_conversion_models.maybe_migration_new_model_weights_token Cover and banner images for models: - model_weights.maybe_banner_media_file_token - model_weights.maybe_cover_media_file_token Avatar and banner images for users: - users.maybe_avatar_media_file_token - users.maybe_cover_media_file_token Sample multimedia for models: - model_weights_samples (new table) --- .../down.sql | 5 + .../up.sql | 10 + .../down.sql | 6 + .../up.sql | 10 + .../down.sql | 5 + .../up.sql | 10 + .../down.sql | 5 + .../up.sql | 10 + .../down.sql | 5 + .../up.sql | 10 + .../down.sql | 6 + .../up.sql | 10 + .../down.sql | 5 + .../up.sql | 10 + .../down.sql | 5 + .../up.sql | 10 + .../down.sql | 5 + .../up.sql | 47 ++++ _sql/migrations_squashed/model_weights.sql | 202 ++++++++++++++++++ .../tts_tables/tts_models.sql | 5 + .../tts_tables/vocoder_models.sql | 5 + .../migrations_squashed/user_tables/users.sql | 8 + .../voice_conversion_models.sql | 5 + 23 files changed, 399 insertions(+) create mode 100644 _sql/migrations/2023-12-15-015254_alter_model_weights_add_old_token/down.sql create mode 100644 _sql/migrations/2023-12-15-015254_alter_model_weights_add_old_token/up.sql create mode 100644 _sql/migrations/2023-12-15-015311_alter_voice_conversion_models_add_new_token/down.sql create mode 100644 _sql/migrations/2023-12-15-015311_alter_voice_conversion_models_add_new_token/up.sql create mode 100644 _sql/migrations/2023-12-15-015319_alter_tts_models_add_new_token/down.sql create mode 100644 _sql/migrations/2023-12-15-015319_alter_tts_models_add_new_token/up.sql create mode 100644 _sql/migrations/2023-12-15-015329_alter_vocoder_models_add_new_token/down.sql create mode 100644 _sql/migrations/2023-12-15-015329_alter_vocoder_models_add_new_token/up.sql create mode 100644 _sql/migrations/2023-12-15-024344_alter_model_weights_add_avatar_media_file_token/down.sql create mode 100644 _sql/migrations/2023-12-15-024344_alter_model_weights_add_avatar_media_file_token/up.sql create mode 100644 _sql/migrations/2023-12-15-024350_alter_model_weights_add_cover_media_file_token/down.sql create mode 100644 _sql/migrations/2023-12-15-024350_alter_model_weights_add_cover_media_file_token/up.sql create mode 100644 _sql/migrations/2023-12-15-034614_alter_users_add_avatar_media_file_token/down.sql create mode 100644 _sql/migrations/2023-12-15-034614_alter_users_add_avatar_media_file_token/up.sql create mode 100644 _sql/migrations/2023-12-15-034644_alter_users_add_cover_media_file_token/down.sql create mode 100644 _sql/migrations/2023-12-15-034644_alter_users_add_cover_media_file_token/up.sql create mode 100644 _sql/migrations/2023-12-15-044416_model_weights_samples/down.sql create mode 100644 _sql/migrations/2023-12-15-044416_model_weights_samples/up.sql create mode 100644 _sql/migrations_squashed/model_weights.sql diff --git a/_sql/migrations/2023-12-15-015254_alter_model_weights_add_old_token/down.sql b/_sql/migrations/2023-12-15-015254_alter_model_weights_add_old_token/down.sql new file mode 100644 index 0000000000..6a822bee27 --- /dev/null +++ b/_sql/migrations/2023-12-15-015254_alter_model_weights_add_old_token/down.sql @@ -0,0 +1,5 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +ALTER TABLE model_weights DROP COLUMN maybe_migration_old_model_token; diff --git a/_sql/migrations/2023-12-15-015254_alter_model_weights_add_old_token/up.sql b/_sql/migrations/2023-12-15-015254_alter_model_weights_add_old_token/up.sql new file mode 100644 index 0000000000..dbcdd42f8b --- /dev/null +++ b/_sql/migrations/2023-12-15-015254_alter_model_weights_add_old_token/up.sql @@ -0,0 +1,10 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +ALTER TABLE model_weights + ADD COLUMN maybe_migration_old_model_token VARCHAR(32) DEFAULT NULL + AFTER cached_user_ratings_last_updated_at; + +ALTER TABLE model_weights + ADD UNIQUE INDEX unique_index_maybe_migration_old_model_token (maybe_migration_old_model_token); diff --git a/_sql/migrations/2023-12-15-015311_alter_voice_conversion_models_add_new_token/down.sql b/_sql/migrations/2023-12-15-015311_alter_voice_conversion_models_add_new_token/down.sql new file mode 100644 index 0000000000..9297e603a6 --- /dev/null +++ b/_sql/migrations/2023-12-15-015311_alter_voice_conversion_models_add_new_token/down.sql @@ -0,0 +1,6 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +ALTER TABLE voice_conversion_models + DROP COLUMN maybe_migration_new_model_weights_token; diff --git a/_sql/migrations/2023-12-15-015311_alter_voice_conversion_models_add_new_token/up.sql b/_sql/migrations/2023-12-15-015311_alter_voice_conversion_models_add_new_token/up.sql new file mode 100644 index 0000000000..b14d521155 --- /dev/null +++ b/_sql/migrations/2023-12-15-015311_alter_voice_conversion_models_add_new_token/up.sql @@ -0,0 +1,10 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +ALTER TABLE voice_conversion_models + ADD COLUMN maybe_migration_new_model_weights_token VARCHAR(32) DEFAULT NULL + AFTER maybe_mod_comments; + +ALTER TABLE voice_conversion_models + ADD UNIQUE INDEX unique_index_maybe_migration_new_model_weights_token (maybe_migration_new_model_weights_token); diff --git a/_sql/migrations/2023-12-15-015319_alter_tts_models_add_new_token/down.sql b/_sql/migrations/2023-12-15-015319_alter_tts_models_add_new_token/down.sql new file mode 100644 index 0000000000..8fae0f7f62 --- /dev/null +++ b/_sql/migrations/2023-12-15-015319_alter_tts_models_add_new_token/down.sql @@ -0,0 +1,5 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +ALTER TABLE tts_models DROP COLUMN maybe_migration_new_model_weights_token; diff --git a/_sql/migrations/2023-12-15-015319_alter_tts_models_add_new_token/up.sql b/_sql/migrations/2023-12-15-015319_alter_tts_models_add_new_token/up.sql new file mode 100644 index 0000000000..569ab1f595 --- /dev/null +++ b/_sql/migrations/2023-12-15-015319_alter_tts_models_add_new_token/up.sql @@ -0,0 +1,10 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +ALTER TABLE tts_models + ADD COLUMN maybe_migration_new_model_weights_token VARCHAR(32) DEFAULT NULL + AFTER maybe_mod_user_token; + +ALTER TABLE tts_models + ADD UNIQUE INDEX unique_index_maybe_migration_new_model_weights_token (maybe_migration_new_model_weights_token); diff --git a/_sql/migrations/2023-12-15-015329_alter_vocoder_models_add_new_token/down.sql b/_sql/migrations/2023-12-15-015329_alter_vocoder_models_add_new_token/down.sql new file mode 100644 index 0000000000..1238b82f67 --- /dev/null +++ b/_sql/migrations/2023-12-15-015329_alter_vocoder_models_add_new_token/down.sql @@ -0,0 +1,5 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +ALTER TABLE vocoder_models DROP COLUMN maybe_migration_new_model_weights_token; diff --git a/_sql/migrations/2023-12-15-015329_alter_vocoder_models_add_new_token/up.sql b/_sql/migrations/2023-12-15-015329_alter_vocoder_models_add_new_token/up.sql new file mode 100644 index 0000000000..f804fad6f2 --- /dev/null +++ b/_sql/migrations/2023-12-15-015329_alter_vocoder_models_add_new_token/up.sql @@ -0,0 +1,10 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +ALTER TABLE vocoder_models + ADD COLUMN maybe_migration_new_model_weights_token VARCHAR(32) DEFAULT NULL + AFTER maybe_mod_user_token; + +ALTER TABLE vocoder_models + ADD UNIQUE INDEX unique_index_maybe_migration_new_model_weights_token (maybe_migration_new_model_weights_token); diff --git a/_sql/migrations/2023-12-15-024344_alter_model_weights_add_avatar_media_file_token/down.sql b/_sql/migrations/2023-12-15-024344_alter_model_weights_add_avatar_media_file_token/down.sql new file mode 100644 index 0000000000..2ae3d04fca --- /dev/null +++ b/_sql/migrations/2023-12-15-024344_alter_model_weights_add_avatar_media_file_token/down.sql @@ -0,0 +1,5 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +ALTER TABLE model_weights DROP COLUMN maybe_avatar_media_file_token; diff --git a/_sql/migrations/2023-12-15-024344_alter_model_weights_add_avatar_media_file_token/up.sql b/_sql/migrations/2023-12-15-024344_alter_model_weights_add_avatar_media_file_token/up.sql new file mode 100644 index 0000000000..2596c1afbf --- /dev/null +++ b/_sql/migrations/2023-12-15-024344_alter_model_weights_add_avatar_media_file_token/up.sql @@ -0,0 +1,10 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +ALTER TABLE model_weights + ADD COLUMN maybe_avatar_media_file_token VARCHAR(32) DEFAULT NULL + AFTER maybe_thumbnail_token; + +ALTER TABLE model_weights + ADD INDEX index_maybe_avatar_media_file_token (maybe_avatar_media_file_token); diff --git a/_sql/migrations/2023-12-15-024350_alter_model_weights_add_cover_media_file_token/down.sql b/_sql/migrations/2023-12-15-024350_alter_model_weights_add_cover_media_file_token/down.sql new file mode 100644 index 0000000000..6458b44595 --- /dev/null +++ b/_sql/migrations/2023-12-15-024350_alter_model_weights_add_cover_media_file_token/down.sql @@ -0,0 +1,6 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +ALTER TABLE model_weights DROP COLUMN maybe_cover_media_file_token; + diff --git a/_sql/migrations/2023-12-15-024350_alter_model_weights_add_cover_media_file_token/up.sql b/_sql/migrations/2023-12-15-024350_alter_model_weights_add_cover_media_file_token/up.sql new file mode 100644 index 0000000000..a04e0a1b18 --- /dev/null +++ b/_sql/migrations/2023-12-15-024350_alter_model_weights_add_cover_media_file_token/up.sql @@ -0,0 +1,10 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +ALTER TABLE model_weights + ADD COLUMN maybe_cover_media_file_token VARCHAR(32) DEFAULT NULL + AFTER maybe_avatar_media_file_token; + +ALTER TABLE model_weights + ADD INDEX index_maybe_cover_media_file_token (maybe_cover_media_file_token); diff --git a/_sql/migrations/2023-12-15-034614_alter_users_add_avatar_media_file_token/down.sql b/_sql/migrations/2023-12-15-034614_alter_users_add_avatar_media_file_token/down.sql new file mode 100644 index 0000000000..2e84ec6bc5 --- /dev/null +++ b/_sql/migrations/2023-12-15-034614_alter_users_add_avatar_media_file_token/down.sql @@ -0,0 +1,5 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +ALTER TABLE users DROP COLUMN maybe_avatar_media_file_token; diff --git a/_sql/migrations/2023-12-15-034614_alter_users_add_avatar_media_file_token/up.sql b/_sql/migrations/2023-12-15-034614_alter_users_add_avatar_media_file_token/up.sql new file mode 100644 index 0000000000..64c9a8a3d5 --- /dev/null +++ b/_sql/migrations/2023-12-15-034614_alter_users_add_avatar_media_file_token/up.sql @@ -0,0 +1,10 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +ALTER TABLE users + ADD COLUMN maybe_avatar_media_file_token VARCHAR(32) DEFAULT NULL + AFTER ip_address_last_update; + +ALTER TABLE users + ADD INDEX index_maybe_avatar_media_file_token (maybe_avatar_media_file_token); diff --git a/_sql/migrations/2023-12-15-034644_alter_users_add_cover_media_file_token/down.sql b/_sql/migrations/2023-12-15-034644_alter_users_add_cover_media_file_token/down.sql new file mode 100644 index 0000000000..45237d79de --- /dev/null +++ b/_sql/migrations/2023-12-15-034644_alter_users_add_cover_media_file_token/down.sql @@ -0,0 +1,5 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +ALTER TABLE users DROP COLUMN maybe_cover_media_file_token; diff --git a/_sql/migrations/2023-12-15-034644_alter_users_add_cover_media_file_token/up.sql b/_sql/migrations/2023-12-15-034644_alter_users_add_cover_media_file_token/up.sql new file mode 100644 index 0000000000..a467e50665 --- /dev/null +++ b/_sql/migrations/2023-12-15-034644_alter_users_add_cover_media_file_token/up.sql @@ -0,0 +1,10 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +ALTER TABLE users + ADD COLUMN maybe_cover_media_file_token VARCHAR(32) DEFAULT NULL + AFTER maybe_avatar_media_file_token; + +ALTER TABLE users + ADD INDEX index_maybe_cover_media_file_token (maybe_cover_media_file_token); diff --git a/_sql/migrations/2023-12-15-044416_model_weights_samples/down.sql b/_sql/migrations/2023-12-15-044416_model_weights_samples/down.sql new file mode 100644 index 0000000000..9834047d63 --- /dev/null +++ b/_sql/migrations/2023-12-15-044416_model_weights_samples/down.sql @@ -0,0 +1,5 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +DROP TABLE model_weights_samples; diff --git a/_sql/migrations/2023-12-15-044416_model_weights_samples/up.sql b/_sql/migrations/2023-12-15-044416_model_weights_samples/up.sql new file mode 100644 index 0000000000..f8d6752a85 --- /dev/null +++ b/_sql/migrations/2023-12-15-044416_model_weights_samples/up.sql @@ -0,0 +1,47 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +CREATE TABLE model_weights_samples ( + -- Not used for anything except replication. + id BIGINT(20) NOT NULL AUTO_INCREMENT, + + -- ========== WEIGHTS CLASSIFICATION ========== + + -- Foreign key to model weights. + -- This is in a composite index with media_file_token to make sure a media file only applies + -- to a given model once. + model_weight_token VARCHAR(32) NOT NULL, + + -- Foreign key to media files + -- This is in a composite index with model_weight_token to make sure a media file only applies + -- to a given model once. + media_file_token VARCHAR(32) NOT NULL, + + -- Information about who set the sample + -- * automation + -- * author + -- * community + set_by VARCHAR(16) NOT NULL, + + -- Incremented with every update. + version INT NOT NULL DEFAULT 0, + + -- ========== TIMESTAMPS ========== + + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + + -- If this is removed by a mod. + -- It completely disappears from the system. + user_deleted_at TIMESTAMP NULL, + mod_deleted_at TIMESTAMP NULL, + + -- INDICES -- + PRIMARY KEY (id), + UNIQUE KEY (model_weight_token, media_file_token), + + KEY index_model_weight_token (model_weight_token), + KEY index_media_file_token (media_file_token) + +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; diff --git a/_sql/migrations_squashed/model_weights.sql b/_sql/migrations_squashed/model_weights.sql new file mode 100644 index 0000000000..dee5401c72 --- /dev/null +++ b/_sql/migrations_squashed/model_weights.sql @@ -0,0 +1,202 @@ +-- NB: This is a manually squashed view of all the CREATE and ALTER statements, +-- with comments attached to the fields for centralized documentation. + +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +-- Every type of fine tuned model that users can upload. +CREATE TABLE model_weights ( + -- Not used for anything except replication. + id BIGINT(20) NOT NULL AUTO_INCREMENT, + + -- Effective "primary key" (PUBLIC) + token VARCHAR(32) NOT NULL, + + -- ========== WEIGHTS CLASSIFICATION ========== + + -- The exact type of weights + -- Currently supported values: + -- * 'hifigan_tt2' - hifigan for Tacotron2; TTS vocoder + -- * 'rvc_v2' - RVC (v2); voice conversion + -- * 'sd_1.5' - Stable Diffusion 1.5; image generation + -- * 'sdxl' - Stable Diffusion XL; image generation + -- * 'so_vits_svc' - SVC; voice conversion + -- * 'tt2' - Tacotron2; TTS + weights_type VARCHAR(32) NOT NULL, + + -- The broader category of the weights + -- Currently supported values: + -- * 'image_generation' (SD1.5, SDXL) + -- * 'text_to_speech' (TT2) + -- * 'vocoder' (Hifigan) + -- * 'voice_conversion' (RVCv2, SVC) + weights_category VARCHAR(32) NOT NULL, + + + -- ========== MODEL DESCRIPTION ========== + + -- The "name" of the model, which might be complicated. + title VARCHAR(255) NOT NULL, + + -- TODO(bt, 2023-12-14): Delete the `maybe_thumbnail_token` column later. + -- We're using other columns instead. + maybe_thumbnail_token VARCHAR(32) DEFAULT NULL, + + -- The "avatar" image is a media file of type image that serves as a + -- small avatar or profile picture icon. + maybe_avatar_media_file_token VARCHAR(32) DEFAULT NULL, + + -- The "cover" image is a media file of type image that covers the + -- top of the page. + maybe_cover_media_file_token VARCHAR(32) DEFAULT NULL, + + -- The description of the model in markdown. + description_markdown TEXT NOT NULL, + + -- Generated HTML (not user-editable). + description_rendered_html TEXT NOT NULL, + + + -- ========== CREATOR DETAILS ========== + + -- The person that created the model. + creator_user_token VARCHAR(32) NOT NULL, + + -- For abuse tracking. + -- Wide enough for IPv4/6. + -- IP address of creator at time of creation. + creator_ip_address VARCHAR(40) NOT NULL, + + -- (THIS MIGHT NOT BE USED) + -- NB: DO NOT SORT! + -- THIS MUST MATCH THE RESPECTIVE JOBS TABLE. + creator_set_visibility ENUM( + 'public', + 'hidden', + 'private' + ) NOT NULL DEFAULT 'public', + + -- The synthetic id associated with this model. + -- These ids are incremented on a per-user basis to help users + -- sequence their own work. They serve no other purpose. + -- "weights" synthetic ids are incremented over all media files + -- creator_weights_synthetic_id BIGINT(20) DEFAULT NULL, + + -- "weights_type" synthetic ids are incremented over a given weight type + -- creator_weights_type_synthetic_id BIGINT(20) DEFAULT NULL, + + -- The last user to edit the model. This could be the creator or a moderator. + -- Check the future audit logs table for more info. + maybe_last_update_user_token VARCHAR(32) DEFAULT NULL, + + + -- ========== IMMUTABLE PROVENANCE AND METADATA ========== + + -- Where the file was originally downloaded (if it was downloaded) + original_download_url VARCHAR(512) DEFAULT NULL, + + -- The filename that was used at upload time (if available) + original_filename VARCHAR(255) DEFAULT NULL, + + -- File characteristics + file_size_bytes INT(10) NOT NULL DEFAULT 0, + + -- Checksum of the original weights file + -- SHA2 hash [SHA2 = CHAR(64), SHA1 = CHAR(40), MD5 = CHAR(32)] + -- Note that SHA2 is a hash family (SHA-228, SHA-256, SHA-384, SHA-512, SHA-512/224, SHA-512/256, ...) + -- and produces different lengths output depending on the choice of algorithm. + file_checksum_sha2 CHAR(64) NOT NULL, + + -- ========== BUCKET STORAGE ========== + + -- The hash for the bucket directory that contains the original upload + -- as well as any associated other files. + -- The bucket filename for the primary file (not including the directory path) is given by: + -- `[{maybe_private_bucket_prefix}]{private_bucket_hash}[{maybe_private_bucket_extension}]` + private_bucket_hash VARCHAR(32) NOT NULL, + + -- An optional prefix on the bucket filename. + -- If present, this will be prepended to the beginning of the bucket filename to access the file. + -- The bucket filename for the primary file (not including the directory path) is given by: + -- `[{maybe_private_bucket_prefix}]{private_directory_hash}[{maybe_private_bucket_extension}]` + maybe_private_bucket_prefix VARCHAR(16) DEFAULT NULL, + + -- An optional appended extension on the bucket filename. + -- If present, this will be appended to the end of the bucket filename to access the file. + -- To allow for flexibility, this extension typically will contain a leading period if + -- the file needs it (eg ".mp4" rather than "mp4")! + -- The bucket filename for the primary file (not including the directory path) is given by: + -- `[{maybe_private_bucket_prefix}]{private_directory_hash}[{maybe_private_bucket_extension}]` + maybe_private_bucket_extension VARCHAR(16) DEFAULT NULL, + + + -- ========== MODERATION DETAILS ========== + + -- Mods may have to approve of vc models for them to show up in a public index. + -- Models can be used by the author (or other parties that know the URL) before + -- they're approved, but unapproved models won't show up in public indices. + -- This is independent of other visibility controls (is_mod_disabled, deleted_at, + -- and creator_set_visibility) + -- is_public_listing_approved BOOLEAN DEFAULT NULL, + + -- Extremely popular models may be locked from deletion or modification by users. + -- is_locked_from_user_modification BOOLEAN NOT NULL DEFAULT FALSE, + + + -- ========== RATING AND RANKING ========== + + -- User ratings are cached on the model, but are *not* a source of truth. + -- Total count only includes "positive" and "negative" votes, not neutral ones. + cached_user_ratings_total_count INT(10) UNSIGNED NOT NULL DEFAULT 0, + + -- Total positive + cached_user_ratings_positive_count INT(10) UNSIGNED NOT NULL DEFAULT 0, + + -- Total negative + cached_user_ratings_negative_count INT(10) UNSIGNED NOT NULL DEFAULT 0, + + -- User ratings are cached on the model, but are *not* a source of truth. + -- Total count only includes "positive" and "negative" votes, not neutral ones. + maybe_cached_user_ratings_ratio FLOAT, + + -- When the cached ratings were last calculated and updated. + cached_user_ratings_last_updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + + + -- ========== MIGRATION DETAILS ========== + + -- If migrated from another table, this is the token of the original model. + maybe_migration_old_model_token VARCHAR(32) DEFAULT NULL, + + + -- ========== VECTOR CLOCK ========== + + -- Incremented with every update. + version INT NOT NULL DEFAULT 0, + + + -- ========== TIMESTAMPS ========== + + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + + -- If this is removed by a mod. + -- It completely disappears from the system. + user_deleted_at TIMESTAMP NULL, + mod_deleted_at TIMESTAMP NULL, + + -- INDICES -- + PRIMARY KEY (id), + UNIQUE KEY (token) + + -- TODO: + -- KEY index_model_type (model_type), + -- KEY fk_maybe_vocoder_token (maybe_vocoder_token), + -- KEY fk_creator_user_token (creator_user_token), + -- KEY index_creator_set_visibility (creator_set_visibility), + -- KEY index_private_bucket_hash (private_bucket_hash), + -- KEY index_is_public_listing_approved (is_public_listing_approved), + -- KEY index_is_locked_from_user_modification (is_locked_from_user_modification) + +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; diff --git a/_sql/migrations_squashed/tts_tables/tts_models.sql b/_sql/migrations_squashed/tts_tables/tts_models.sql index 493d2c3cd2..ca6c71e565 100644 --- a/_sql/migrations_squashed/tts_tables/tts_models.sql +++ b/_sql/migrations_squashed/tts_tables/tts_models.sql @@ -200,6 +200,11 @@ CREATE TABLE tts_models ( -- The last moderator that made changes. maybe_mod_user_token VARCHAR(32) DEFAULT NULL, + -- ========== MIGRATION DETAILS ========== + + -- If migrated to model_weights, this is the new token + maybe_migration_new_model_weights_token VARCHAR(32) DEFAULT NULL, + -- ========== VECTOR CLOCK ========== -- Incremented with every update. diff --git a/_sql/migrations_squashed/tts_tables/vocoder_models.sql b/_sql/migrations_squashed/tts_tables/vocoder_models.sql index d11793c780..5c4a9c38ac 100644 --- a/_sql/migrations_squashed/tts_tables/vocoder_models.sql +++ b/_sql/migrations_squashed/tts_tables/vocoder_models.sql @@ -99,6 +99,11 @@ CREATE TABLE vocoder_models ( -- The last moderator that made changes. maybe_mod_user_token VARCHAR(32) DEFAULT NULL, + -- ========== MIGRATION DETAILS ========== + + -- If migrated to model_weights, this is the new token + maybe_migration_new_model_weights_token VARCHAR(32) DEFAULT NULL, + -- ========== VECTOR CLOCK ========== -- Incremented with every update. diff --git a/_sql/migrations_squashed/user_tables/users.sql b/_sql/migrations_squashed/user_tables/users.sql index 43b6805adb..1ea5fca0ef 100644 --- a/_sql/migrations_squashed/user_tables/users.sql +++ b/_sql/migrations_squashed/user_tables/users.sql @@ -53,6 +53,14 @@ CREATE TABLE users ( -- ========== DISPLAY / PROFILE ========== + -- The "avatar" image is a media file of type image that serves as a + -- small avatar or profile picture icon. + maybe_avatar_media_file_token VARCHAR(32) DEFAULT NULL, + + -- The "cover" image is a media file of type image that covers the + -- top of the page. + maybe_cover_media_file_token VARCHAR(32) DEFAULT NULL, + -- Gravatar image hashes are precomputed. email_gravatar_hash CHAR(32) NOT NULL, diff --git a/_sql/migrations_squashed/voice_conversion_models.sql b/_sql/migrations_squashed/voice_conversion_models.sql index cff4f387a9..d28f338ae9 100644 --- a/_sql/migrations_squashed/voice_conversion_models.sql +++ b/_sql/migrations_squashed/voice_conversion_models.sql @@ -121,6 +121,11 @@ CREATE TABLE voice_conversion_models ( -- If a moderator has comments. maybe_mod_comments VARCHAR(255) DEFAULT NULL, + -- ========== MIGRATION DETAILS ========== + + -- If migrated to model_weights, this is the new token + maybe_migration_new_model_weights_token VARCHAR(32) DEFAULT NULL, + -- ========== VECTOR CLOCK ========== -- Incremented with every update. From 11e3a4e429e1a016ef94c1a5384e57b986eac03e Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Fri, 15 Dec 2023 12:47:33 -0500 Subject: [PATCH 051/124] rename `model_weights_samples` -> `model_weights_preview_samples` - doing this before anyone else runs these migrations - also added "squashed" documentation on the model_weights and associated tables - also added (commented) good indices for model_weights --- .../down.sql | 2 +- .../up.sql | 2 +- .../{ => model_weights}/model_weights.sql | 11 ++- ...model_weights_image_generation_details.sql | 50 +++++++++++++ .../model_weights_preview_samples.sql | 47 ++++++++++++ .../model_weights_tts_details.sql | 73 +++++++++++++++++++ .../model_weights_vocoder_details.sql | 50 +++++++++++++ ...model_weights_voice_conversion_details.sql | 62 ++++++++++++++++ 8 files changed, 289 insertions(+), 8 deletions(-) rename _sql/migrations/{2023-12-15-044416_model_weights_samples => 2023-12-15-044416_model_weights_preview_samples}/down.sql (75%) rename _sql/migrations/{2023-12-15-044416_model_weights_samples => 2023-12-15-044416_model_weights_preview_samples}/up.sql (96%) rename _sql/migrations_squashed/{ => model_weights}/model_weights.sql (95%) create mode 100644 _sql/migrations_squashed/model_weights/model_weights_image_generation_details.sql create mode 100644 _sql/migrations_squashed/model_weights/model_weights_preview_samples.sql create mode 100644 _sql/migrations_squashed/model_weights/model_weights_tts_details.sql create mode 100644 _sql/migrations_squashed/model_weights/model_weights_vocoder_details.sql create mode 100644 _sql/migrations_squashed/model_weights/model_weights_voice_conversion_details.sql diff --git a/_sql/migrations/2023-12-15-044416_model_weights_samples/down.sql b/_sql/migrations/2023-12-15-044416_model_weights_preview_samples/down.sql similarity index 75% rename from _sql/migrations/2023-12-15-044416_model_weights_samples/down.sql rename to _sql/migrations/2023-12-15-044416_model_weights_preview_samples/down.sql index 9834047d63..a28ccc7763 100644 --- a/_sql/migrations/2023-12-15-044416_model_weights_samples/down.sql +++ b/_sql/migrations/2023-12-15-044416_model_weights_preview_samples/down.sql @@ -2,4 +2,4 @@ -- noinspection SqlNoDataSourceInspectionForFile -- noinspection SqlResolveForFile -DROP TABLE model_weights_samples; +DROP TABLE model_weights_preview_samples; diff --git a/_sql/migrations/2023-12-15-044416_model_weights_samples/up.sql b/_sql/migrations/2023-12-15-044416_model_weights_preview_samples/up.sql similarity index 96% rename from _sql/migrations/2023-12-15-044416_model_weights_samples/up.sql rename to _sql/migrations/2023-12-15-044416_model_weights_preview_samples/up.sql index f8d6752a85..a4f5276caa 100644 --- a/_sql/migrations/2023-12-15-044416_model_weights_samples/up.sql +++ b/_sql/migrations/2023-12-15-044416_model_weights_preview_samples/up.sql @@ -2,7 +2,7 @@ -- noinspection SqlNoDataSourceInspectionForFile -- noinspection SqlResolveForFile -CREATE TABLE model_weights_samples ( +CREATE TABLE model_weights_preview_samples ( -- Not used for anything except replication. id BIGINT(20) NOT NULL AUTO_INCREMENT, diff --git a/_sql/migrations_squashed/model_weights.sql b/_sql/migrations_squashed/model_weights/model_weights.sql similarity index 95% rename from _sql/migrations_squashed/model_weights.sql rename to _sql/migrations_squashed/model_weights/model_weights.sql index dee5401c72..f9e0bf4836 100644 --- a/_sql/migrations_squashed/model_weights.sql +++ b/_sql/migrations_squashed/model_weights/model_weights.sql @@ -190,13 +190,12 @@ CREATE TABLE model_weights ( PRIMARY KEY (id), UNIQUE KEY (token) - -- TODO: - -- KEY index_model_type (model_type), - -- KEY fk_maybe_vocoder_token (maybe_vocoder_token), + -- TODO (this set should be good to go): + -- KEY index_weights_type (weights_type), + -- KEY index_weights_category (weights_category), -- KEY fk_creator_user_token (creator_user_token), -- KEY index_creator_set_visibility (creator_set_visibility), - -- KEY index_private_bucket_hash (private_bucket_hash), - -- KEY index_is_public_listing_approved (is_public_listing_approved), - -- KEY index_is_locked_from_user_modification (is_locked_from_user_modification) + -- KEY fk_maybe_avatar_media_file_token (maybe_avatar_media_file_token), + -- KEY fk_maybe_cover_media_file_token (maybe_cover_media_file_token) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; diff --git a/_sql/migrations_squashed/model_weights/model_weights_image_generation_details.sql b/_sql/migrations_squashed/model_weights/model_weights_image_generation_details.sql new file mode 100644 index 0000000000..26b3c9b7ba --- /dev/null +++ b/_sql/migrations_squashed/model_weights/model_weights_image_generation_details.sql @@ -0,0 +1,50 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +-- Every type of fine tuned model that users can upload. +CREATE TABLE model_weights_image_generation_details ( + -- Not used for anything except replication. + id BIGINT(20) NOT NULL AUTO_INCREMENT, + + -- Simultaneous primary and foreign key. + -- This should match a single record in the `model_weights` table. + -- This turns this table into a polymorphic extension table. + model_weights_token VARCHAR(32) NOT NULL, + + + -- ========== IMAGE GENERATION MODEL METADATA ========== + + -- RVC (v2) specific - whether the model has an index file associated with it + -- These files improve the quality of the results. + vc_has_index_file BOOLEAN NOT NULL DEFAULT FALSE, + + -- ========== VECTOR CLOCK ========== + + -- Incremented with every update. + version INT NOT NULL DEFAULT 0, + + + -- ========== TIMESTAMPS ========== + + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + + -- If this is removed by a mod. + -- It completely disappears from the system. + user_deleted_at TIMESTAMP NULL, + mod_deleted_at TIMESTAMP NULL, + + -- INDICES -- + PRIMARY KEY (id), + UNIQUE KEY (model_weights_token) + -- TODO: + -- KEY index_model_type (model_type), + -- KEY fk_maybe_vocoder_token (maybe_vocoder_token), + -- KEY fk_creator_user_token (creator_user_token), + -- KEY index_creator_set_visibility (creator_set_visibility), + -- KEY index_private_bucket_hash (private_bucket_hash), + -- KEY index_is_public_listing_approved (is_public_listing_approved), + -- KEY index_is_locked_from_user_modification (is_locked_from_user_modification) + +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; diff --git a/_sql/migrations_squashed/model_weights/model_weights_preview_samples.sql b/_sql/migrations_squashed/model_weights/model_weights_preview_samples.sql new file mode 100644 index 0000000000..a4f5276caa --- /dev/null +++ b/_sql/migrations_squashed/model_weights/model_weights_preview_samples.sql @@ -0,0 +1,47 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +CREATE TABLE model_weights_preview_samples ( + -- Not used for anything except replication. + id BIGINT(20) NOT NULL AUTO_INCREMENT, + + -- ========== WEIGHTS CLASSIFICATION ========== + + -- Foreign key to model weights. + -- This is in a composite index with media_file_token to make sure a media file only applies + -- to a given model once. + model_weight_token VARCHAR(32) NOT NULL, + + -- Foreign key to media files + -- This is in a composite index with model_weight_token to make sure a media file only applies + -- to a given model once. + media_file_token VARCHAR(32) NOT NULL, + + -- Information about who set the sample + -- * automation + -- * author + -- * community + set_by VARCHAR(16) NOT NULL, + + -- Incremented with every update. + version INT NOT NULL DEFAULT 0, + + -- ========== TIMESTAMPS ========== + + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + + -- If this is removed by a mod. + -- It completely disappears from the system. + user_deleted_at TIMESTAMP NULL, + mod_deleted_at TIMESTAMP NULL, + + -- INDICES -- + PRIMARY KEY (id), + UNIQUE KEY (model_weight_token, media_file_token), + + KEY index_model_weight_token (model_weight_token), + KEY index_media_file_token (media_file_token) + +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; diff --git a/_sql/migrations_squashed/model_weights/model_weights_tts_details.sql b/_sql/migrations_squashed/model_weights/model_weights_tts_details.sql new file mode 100644 index 0000000000..540e534532 --- /dev/null +++ b/_sql/migrations_squashed/model_weights/model_weights_tts_details.sql @@ -0,0 +1,73 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +-- Extra metadata on tts models +CREATE TABLE model_weights_tts_details ( + -- Not used for anything except replication. + id BIGINT(20) NOT NULL AUTO_INCREMENT, + + -- Simultaneous primary and foreign key. + -- This should match a single record in the `model_weights` table. + -- This turns this table into a polymorphic extension table. + model_weights_token VARCHAR(32) NOT NULL, + + -- ========== TTS MODEL METADATA ========== + + -- The full IETF BCP47 language tag (eg. en, en-US, es-419, ja-JP, pt, etc.) + -- (Not that it matters apart from categorization, since voice conversion is universal.) + ietf_language_tag VARCHAR(64) NOT NULL DEFAULT 'en', + + -- The IETF BCP47 language tag's primary language subtag (eg. "es-419" becomes "es") + -- (Not that it matters apart from categorization, since voice conversion is universal.) + ietf_primary_language_subtag VARCHAR(12) NOT NULL DEFAULT 'en', + + -- This is for Tacotron2, specifically. + -- The name of the type of pipeline to use, eg "legacy_fakeyou", "legacy_vocodes", "english_v1", etc. + -- New pipelines may be added at any point in the future and the source of truth for them will mostly + -- live in the `storyteller-ml` repository. + -- Older models and brand new models will have this field set to null, and we'll infer which value to + -- lazily backfill based on the creation date and language setting. + -- tts_text_pipeline_type VARCHAR(64) DEFAULT NULL, + + -- If true, multiply the mel outputs before being vocoded by a globally default constant. + use_default_mel_multiply_factor BOOLEAN NOT NULL DEFAULT FALSE, + + -- If not null, multiply the mel outputs before being vocoded by this value. + -- This is used instead of the default if `tts_use_default_mel_multiply_factor` is + -- set (ie. `tts_use_default_mel_multiply_factor` is ignored and this custom value is used instead) + maybe_custom_mel_multiply_factor DOUBLE DEFAULT NULL, + + -- If set, use a different pretrained vocoder. + -- If not set, use the website default. (Currently HifiGan-SS) + maybe_default_pretrained_vocoder VARCHAR(64) DEFAULT NULL, + + -- If set, we'll use a custom vocoder (from table vocoder_models) instead of a default vocoder. + -- If not set, we'll use `maybe_default_pretrained_vocoder` (or the website default). + maybe_custom_vocoder_token VARCHAR(32) DEFAULT NULL, + + + -- ========== VECTOR CLOCK ========== + + -- Incremented with every update. + version INT NOT NULL DEFAULT 0, + + + -- ========== TIMESTAMPS ========== + + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + + -- INDICES -- + PRIMARY KEY (id), + UNIQUE KEY (model_weights_token) + -- TODO: + -- KEY index_model_type (model_type), + -- KEY fk_maybe_vocoder_token (maybe_vocoder_token), + -- KEY fk_creator_user_token (creator_user_token), + -- KEY index_creator_set_visibility (creator_set_visibility), + -- KEY index_private_bucket_hash (private_bucket_hash), + -- KEY index_is_public_listing_approved (is_public_listing_approved), + -- KEY index_is_locked_from_user_modification (is_locked_from_user_modification) + +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; diff --git a/_sql/migrations_squashed/model_weights/model_weights_vocoder_details.sql b/_sql/migrations_squashed/model_weights/model_weights_vocoder_details.sql new file mode 100644 index 0000000000..f04ac7f346 --- /dev/null +++ b/_sql/migrations_squashed/model_weights/model_weights_vocoder_details.sql @@ -0,0 +1,50 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +-- Every type of fine tuned model that users can upload. +CREATE TABLE model_weights_vocoder_details ( + -- Not used for anything except replication. + id BIGINT(20) NOT NULL AUTO_INCREMENT, + + -- Simultaneous primary and foreign key. + -- This should match a single record in the `model_weights` table. + -- This turns this table into a polymorphic extension table. + model_weights_token VARCHAR(32) NOT NULL, + + + -- ========== VOCODER MODEL METADATA ========== + + -- Whether the vocoder is recommended for use + -- vocoder_is_staff_recommended BOOLEAN NOT NULL DEFAULT FALSE, + + + -- ========== VECTOR CLOCK ========== + + -- Incremented with every update. + version INT NOT NULL DEFAULT 0, + + + -- ========== TIMESTAMPS ========== + + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + + -- If this is removed by a mod. + -- It completely disappears from the system. + user_deleted_at TIMESTAMP NULL, + mod_deleted_at TIMESTAMP NULL, + + -- INDICES -- + PRIMARY KEY (id), + UNIQUE KEY (model_weights_token) + -- TODO: + -- KEY index_model_type (model_type), + -- KEY fk_maybe_vocoder_token (maybe_vocoder_token), + -- KEY fk_creator_user_token (creator_user_token), + -- KEY index_creator_set_visibility (creator_set_visibility), + -- KEY index_private_bucket_hash (private_bucket_hash), + -- KEY index_is_public_listing_approved (is_public_listing_approved), + -- KEY index_is_locked_from_user_modification (is_locked_from_user_modification) + +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; diff --git a/_sql/migrations_squashed/model_weights/model_weights_voice_conversion_details.sql b/_sql/migrations_squashed/model_weights/model_weights_voice_conversion_details.sql new file mode 100644 index 0000000000..8dd5e0c9a1 --- /dev/null +++ b/_sql/migrations_squashed/model_weights/model_weights_voice_conversion_details.sql @@ -0,0 +1,62 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +-- Every type of fine tuned model that users can upload. +CREATE TABLE model_weights_voice_conversion_details ( + -- Not used for anything except replication. + id BIGINT(20) NOT NULL AUTO_INCREMENT, + + -- Simultaneous primary and foreign key. + -- This should match a single record in the `model_weights` table. + -- This turns this table into a polymorphic extension table. + model_weights_token VARCHAR(32) NOT NULL, + + + -- ========== VOICE CONVERSION MODEL METADATA ========== + + -- The full IETF BCP47 language tag (eg. en, en-US, es-419, ja-JP, pt, etc.) + -- (Not that it matters apart from categorization, since voice conversion is universal.) + ietf_language_tag VARCHAR(64) NOT NULL DEFAULT 'en', + + -- The IETF BCP47 language tag's primary language subtag (eg. "es-419" becomes "es") + -- (Not that it matters apart from categorization, since voice conversion is universal.) + ietf_primary_language_subtag VARCHAR(12) NOT NULL DEFAULT 'en', + + -- RVC (v2) specific - whether the model has an index file associated with it + -- These files improve the quality of the results. + has_index_file BOOLEAN NOT NULL DEFAULT FALSE, + + -- Pitch algorithm to use by default + default_pitch_algorithm VARCHAR(64) DEFAULT NULL, + + + -- ========== VECTOR CLOCK ========== + + -- Incremented with every update. + version INT NOT NULL DEFAULT 0, + + + -- ========== TIMESTAMPS ========== + + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + + -- If this is removed by a mod. + -- It completely disappears from the system. + user_deleted_at TIMESTAMP NULL, + mod_deleted_at TIMESTAMP NULL, + + -- INDICES -- + PRIMARY KEY (id), + UNIQUE KEY (model_weights_token) + -- TODO: + -- KEY index_model_type (model_type), + -- KEY fk_maybe_vocoder_token (maybe_vocoder_token), + -- KEY fk_creator_user_token (creator_user_token), + -- KEY index_creator_set_visibility (creator_set_visibility), + -- KEY index_private_bucket_hash (private_bucket_hash), + -- KEY index_is_public_listing_approved (is_public_listing_approved), + -- KEY index_is_locked_from_user_modification (is_locked_from_user_modification) + +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; From 98fa0a67ea11b27bc1a841e3306afd6ab0b1c1c8 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Fri, 15 Dec 2023 13:33:14 -0500 Subject: [PATCH 052/124] rename extension tables --- .../down.sql | 9 +++++++++ .../up.sql | 9 +++++++++ ...model_weights_extension_image_generation_details.sql} | 2 +- ...tails.sql => model_weights_extension_tts_details.sql} | 2 +- ...s.sql => model_weights_extension_vocoder_details.sql} | 2 +- ...model_weights_extension_voice_conversion_details.sql} | 2 +- 6 files changed, 22 insertions(+), 4 deletions(-) create mode 100644 _sql/migrations/2023-12-15-182157_rename_model_weights_extension_tables/down.sql create mode 100644 _sql/migrations/2023-12-15-182157_rename_model_weights_extension_tables/up.sql rename _sql/migrations_squashed/model_weights/{model_weights_image_generation_details.sql => model_weights_extension_image_generation_details.sql} (96%) rename _sql/migrations_squashed/model_weights/{model_weights_tts_details.sql => model_weights_extension_tts_details.sql} (98%) rename _sql/migrations_squashed/model_weights/{model_weights_vocoder_details.sql => model_weights_extension_vocoder_details.sql} (96%) rename _sql/migrations_squashed/model_weights/{model_weights_voice_conversion_details.sql => model_weights_extension_voice_conversion_details.sql} (97%) diff --git a/_sql/migrations/2023-12-15-182157_rename_model_weights_extension_tables/down.sql b/_sql/migrations/2023-12-15-182157_rename_model_weights_extension_tables/down.sql new file mode 100644 index 0000000000..842ea3a25d --- /dev/null +++ b/_sql/migrations/2023-12-15-182157_rename_model_weights_extension_tables/down.sql @@ -0,0 +1,9 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +-- I'm doing this to visually align these tables and sort them together, because there will likely be other model_weights_* tables. +RENAME TABLE model_weights_extension_image_generation_details TO model_weights_image_generation_details; +RENAME TABLE model_weights_extension_tts_details TO model_weights_tts_details; +RENAME TABLE model_weights_extension_vocoder_details TO model_weights_vocoder_details; +RENAME TABLE model_weights_extension_voice_conversion_details TO model_weights_voice_conversion_details; diff --git a/_sql/migrations/2023-12-15-182157_rename_model_weights_extension_tables/up.sql b/_sql/migrations/2023-12-15-182157_rename_model_weights_extension_tables/up.sql new file mode 100644 index 0000000000..8a9490ffcf --- /dev/null +++ b/_sql/migrations/2023-12-15-182157_rename_model_weights_extension_tables/up.sql @@ -0,0 +1,9 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +-- I'm doing this to visually align these tables and sort them together, because there will likely be other model_weights_* tables. +RENAME TABLE model_weights_image_generation_details TO model_weights_extension_image_generation_details; +RENAME TABLE model_weights_tts_details TO model_weights_extension_tts_details; +RENAME TABLE model_weights_vocoder_details TO model_weights_extension_vocoder_details; +RENAME TABLE model_weights_voice_conversion_details TO model_weights_extension_voice_conversion_details; diff --git a/_sql/migrations_squashed/model_weights/model_weights_image_generation_details.sql b/_sql/migrations_squashed/model_weights/model_weights_extension_image_generation_details.sql similarity index 96% rename from _sql/migrations_squashed/model_weights/model_weights_image_generation_details.sql rename to _sql/migrations_squashed/model_weights/model_weights_extension_image_generation_details.sql index 26b3c9b7ba..44d1ee4081 100644 --- a/_sql/migrations_squashed/model_weights/model_weights_image_generation_details.sql +++ b/_sql/migrations_squashed/model_weights/model_weights_extension_image_generation_details.sql @@ -3,7 +3,7 @@ -- noinspection SqlResolveForFile -- Every type of fine tuned model that users can upload. -CREATE TABLE model_weights_image_generation_details ( +CREATE TABLE model_weights_extension_image_generation_details ( -- Not used for anything except replication. id BIGINT(20) NOT NULL AUTO_INCREMENT, diff --git a/_sql/migrations_squashed/model_weights/model_weights_tts_details.sql b/_sql/migrations_squashed/model_weights/model_weights_extension_tts_details.sql similarity index 98% rename from _sql/migrations_squashed/model_weights/model_weights_tts_details.sql rename to _sql/migrations_squashed/model_weights/model_weights_extension_tts_details.sql index 540e534532..01478a453f 100644 --- a/_sql/migrations_squashed/model_weights/model_weights_tts_details.sql +++ b/_sql/migrations_squashed/model_weights/model_weights_extension_tts_details.sql @@ -3,7 +3,7 @@ -- noinspection SqlResolveForFile -- Extra metadata on tts models -CREATE TABLE model_weights_tts_details ( +CREATE TABLE model_weights_extension_tts_details ( -- Not used for anything except replication. id BIGINT(20) NOT NULL AUTO_INCREMENT, diff --git a/_sql/migrations_squashed/model_weights/model_weights_vocoder_details.sql b/_sql/migrations_squashed/model_weights/model_weights_extension_vocoder_details.sql similarity index 96% rename from _sql/migrations_squashed/model_weights/model_weights_vocoder_details.sql rename to _sql/migrations_squashed/model_weights/model_weights_extension_vocoder_details.sql index f04ac7f346..c3e4625f43 100644 --- a/_sql/migrations_squashed/model_weights/model_weights_vocoder_details.sql +++ b/_sql/migrations_squashed/model_weights/model_weights_extension_vocoder_details.sql @@ -3,7 +3,7 @@ -- noinspection SqlResolveForFile -- Every type of fine tuned model that users can upload. -CREATE TABLE model_weights_vocoder_details ( +CREATE TABLE model_weights_extension_vocoder_details ( -- Not used for anything except replication. id BIGINT(20) NOT NULL AUTO_INCREMENT, diff --git a/_sql/migrations_squashed/model_weights/model_weights_voice_conversion_details.sql b/_sql/migrations_squashed/model_weights/model_weights_extension_voice_conversion_details.sql similarity index 97% rename from _sql/migrations_squashed/model_weights/model_weights_voice_conversion_details.sql rename to _sql/migrations_squashed/model_weights/model_weights_extension_voice_conversion_details.sql index 8dd5e0c9a1..e32c19ca57 100644 --- a/_sql/migrations_squashed/model_weights/model_weights_voice_conversion_details.sql +++ b/_sql/migrations_squashed/model_weights/model_weights_extension_voice_conversion_details.sql @@ -3,7 +3,7 @@ -- noinspection SqlResolveForFile -- Every type of fine tuned model that users can upload. -CREATE TABLE model_weights_voice_conversion_details ( +CREATE TABLE model_weights_extension_voice_conversion_details ( -- Not used for anything except replication. id BIGINT(20) NOT NULL AUTO_INCREMENT, From a6806d36166d737717f7f6bca41697d51991789e Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Fri, 15 Dec 2023 13:57:22 -0500 Subject: [PATCH 053/124] indices on model_weights and users (there weren't any on model_weights!) --- .../down.sql | 10 ++++++++++ .../up.sql | 10 ++++++++++ .../down.sql | 6 ++++++ .../up.sql | 6 ++++++ .../model_weights/model_weights.sql | 15 +++++++-------- _sql/migrations_squashed/user_tables/users.sql | 4 +++- 6 files changed, 42 insertions(+), 9 deletions(-) create mode 100644 _sql/migrations/2023-12-15-184731_alter_model_weights_add_indices/down.sql create mode 100644 _sql/migrations/2023-12-15-184731_alter_model_weights_add_indices/up.sql create mode 100644 _sql/migrations/2023-12-15-185147_alter_users_add_indices/down.sql create mode 100644 _sql/migrations/2023-12-15-185147_alter_users_add_indices/up.sql diff --git a/_sql/migrations/2023-12-15-184731_alter_model_weights_add_indices/down.sql b/_sql/migrations/2023-12-15-184731_alter_model_weights_add_indices/down.sql new file mode 100644 index 0000000000..6f900e0a96 --- /dev/null +++ b/_sql/migrations/2023-12-15-184731_alter_model_weights_add_indices/down.sql @@ -0,0 +1,10 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +DROP INDEX index_weights_type ON model_weights; +DROP INDEX index_weights_category ON model_weights; +DROP INDEX fk_creator_user_token ON model_weights; +DROP INDEX index_creator_set_visibility ON model_weights; +DROP INDEX fk_maybe_avatar_media_file_token ON model_weights; +DROP INDEX fk_maybe_cover_media_file_token ON model_weights; diff --git a/_sql/migrations/2023-12-15-184731_alter_model_weights_add_indices/up.sql b/_sql/migrations/2023-12-15-184731_alter_model_weights_add_indices/up.sql new file mode 100644 index 0000000000..125b175883 --- /dev/null +++ b/_sql/migrations/2023-12-15-184731_alter_model_weights_add_indices/up.sql @@ -0,0 +1,10 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +CREATE INDEX index_weights_type ON model_weights (weights_type); +CREATE INDEX index_weights_category ON model_weights (weights_category); +CREATE INDEX fk_creator_user_token ON model_weights (creator_user_token); +CREATE INDEX index_creator_set_visibility ON model_weights (creator_set_visibility); +CREATE INDEX fk_maybe_avatar_media_file_token ON model_weights (maybe_avatar_media_file_token); +CREATE INDEX fk_maybe_cover_media_file_token ON model_weights (maybe_cover_media_file_token); diff --git a/_sql/migrations/2023-12-15-185147_alter_users_add_indices/down.sql b/_sql/migrations/2023-12-15-185147_alter_users_add_indices/down.sql new file mode 100644 index 0000000000..ce09b66809 --- /dev/null +++ b/_sql/migrations/2023-12-15-185147_alter_users_add_indices/down.sql @@ -0,0 +1,6 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +DROP INDEX fk_maybe_avatar_media_file_token ON users; +DROP INDEX fk_maybe_cover_media_file_token ON users; diff --git a/_sql/migrations/2023-12-15-185147_alter_users_add_indices/up.sql b/_sql/migrations/2023-12-15-185147_alter_users_add_indices/up.sql new file mode 100644 index 0000000000..12565c806a --- /dev/null +++ b/_sql/migrations/2023-12-15-185147_alter_users_add_indices/up.sql @@ -0,0 +1,6 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +CREATE INDEX fk_maybe_avatar_media_file_token ON users (maybe_avatar_media_file_token); +CREATE INDEX fk_maybe_cover_media_file_token ON users (maybe_cover_media_file_token); diff --git a/_sql/migrations_squashed/model_weights/model_weights.sql b/_sql/migrations_squashed/model_weights/model_weights.sql index f9e0bf4836..f17a5e1067 100644 --- a/_sql/migrations_squashed/model_weights/model_weights.sql +++ b/_sql/migrations_squashed/model_weights/model_weights.sql @@ -188,14 +188,13 @@ CREATE TABLE model_weights ( -- INDICES -- PRIMARY KEY (id), - UNIQUE KEY (token) + UNIQUE KEY (token), - -- TODO (this set should be good to go): - -- KEY index_weights_type (weights_type), - -- KEY index_weights_category (weights_category), - -- KEY fk_creator_user_token (creator_user_token), - -- KEY index_creator_set_visibility (creator_set_visibility), - -- KEY fk_maybe_avatar_media_file_token (maybe_avatar_media_file_token), - -- KEY fk_maybe_cover_media_file_token (maybe_cover_media_file_token) + KEY index_weights_type (weights_type), + KEY index_weights_category (weights_category), + KEY fk_creator_user_token (creator_user_token), + KEY index_creator_set_visibility (creator_set_visibility), + KEY fk_maybe_avatar_media_file_token (maybe_avatar_media_file_token), + KEY fk_maybe_cover_media_file_token (maybe_cover_media_file_token) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; diff --git a/_sql/migrations_squashed/user_tables/users.sql b/_sql/migrations_squashed/user_tables/users.sql index 1ea5fca0ef..874b0028be 100644 --- a/_sql/migrations_squashed/user_tables/users.sql +++ b/_sql/migrations_squashed/user_tables/users.sql @@ -170,7 +170,9 @@ CREATE TABLE users ( UNIQUE KEY (token), UNIQUE KEY (username), UNIQUE KEY (email_address), - KEY fk_user_role_slug (user_role_slug) + KEY fk_user_role_slug (user_role_slug), + KEY fk_maybe_avatar_media_file_token (maybe_avatar_media_file_token), + KEY fk_maybe_cover_media_file_token (maybe_cover_media_file_token) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; From 0e1f6187bfd9cef73404db3dc95de6ee5b0f11cc Mon Sep 17 00:00:00 2001 From: Michael Chung Date: Fri, 15 Dec 2023 16:29:36 -0500 Subject: [PATCH 054/124] Weights path working on the generic version. --- .../src/public/files/bucket_directory.rs | 0 .../src/public/files/media_descriptor.rs | 0 .../src/public/files/weights_descriptor.rs | 0 crates/_types/buckets/src/public/mod.rs | 3 +- .../public/weight_files/bucket_directory.rs | 75 +++++++++ .../public/weight_files/bucket_file_path.rs | 142 ++++++++++++++++++ .../buckets/src/public/weight_files/mod.rs | 2 + .../dev_database_seed/src/seeding/pythonex.py | 33 ++++ .../src/seeding/seed_model_weights.rs | 6 +- 9 files changed, 257 insertions(+), 4 deletions(-) create mode 100644 crates/_types/buckets/src/public/files/bucket_directory.rs create mode 100644 crates/_types/buckets/src/public/files/media_descriptor.rs create mode 100644 crates/_types/buckets/src/public/files/weights_descriptor.rs create mode 100644 crates/_types/buckets/src/public/weight_files/bucket_directory.rs create mode 100644 crates/_types/buckets/src/public/weight_files/bucket_file_path.rs create mode 100644 crates/_types/buckets/src/public/weight_files/mod.rs create mode 100644 crates/cli/dev_database_seed/src/seeding/pythonex.py diff --git a/crates/_types/buckets/src/public/files/bucket_directory.rs b/crates/_types/buckets/src/public/files/bucket_directory.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/crates/_types/buckets/src/public/files/media_descriptor.rs b/crates/_types/buckets/src/public/files/media_descriptor.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/crates/_types/buckets/src/public/files/weights_descriptor.rs b/crates/_types/buckets/src/public/files/weights_descriptor.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/crates/_types/buckets/src/public/mod.rs b/crates/_types/buckets/src/public/mod.rs index fcceb68d9b..97aca68159 100644 --- a/crates/_types/buckets/src/public/mod.rs +++ b/crates/_types/buckets/src/public/mod.rs @@ -2,4 +2,5 @@ pub mod media_files; pub mod media_uploads; pub mod public_path; pub mod voice_conversion_results; -pub mod weight_uploads; \ No newline at end of file +pub mod weight_uploads; +pub mod weight_files; \ No newline at end of file diff --git a/crates/_types/buckets/src/public/weight_files/bucket_directory.rs b/crates/_types/buckets/src/public/weight_files/bucket_directory.rs new file mode 100644 index 0000000000..5c1bb2445c --- /dev/null +++ b/crates/_types/buckets/src/public/weight_files/bucket_directory.rs @@ -0,0 +1,75 @@ +use crockford::crockford_entropy_lower; + +use crate::public::public_path::PublicPath; +use crate::util::hashed_directory_path_long_string::hashed_directory_path_long_string; + +// TODO: Generate these from a macro. +// TODO: Use a central path registry for quick reference +const WEIGHT_FILE_DIRECTORY: &str = "/weights"; + +/// Directory for user weight uploads. +/// Each uploaded file gets its own directory so that we can store the original +/// file alongside re-processed derivatives. +#[derive(Clone)] +pub struct WeightFileBucketDirectory { + object_hash: String, + directory: String, +} + +impl PublicPath for WeightFileBucketDirectory {} + +impl WeightFileBucketDirectory { + + pub fn generate_new() -> Self { + let entropy = crockford_entropy_lower(32); + Self::from_object_hash(&entropy) + } + + pub fn from_object_hash(object_hash: &str) -> Self { + // TODO: Path construction could be cleaner. + let middle = hashed_directory_path_long_string(object_hash); + let directory = format!("{}/{}{}", WEIGHT_FILE_DIRECTORY, middle, object_hash); + Self { + object_hash: object_hash.to_string(), + directory, + } + } + + pub fn get_directory_path_str(&self) -> &str { + &self.directory + } + + pub fn get_object_hash(&self) -> &str { + &self.object_hash + } +} + +#[cfg(test)] +mod tests { + use crate::public::weight_files::bucket_directory::WeightFileBucketDirectory; + + #[test] + pub fn generate_new_entropy() { + let directory = WeightFileBucketDirectory::generate_new(); + assert_eq!(directory.get_object_hash().len(), 32); + } + + #[test] + pub fn get_directory_path_str() { + let directory = WeightFileBucketDirectory::from_object_hash("abcdefghijk"); + assert_eq!(directory.get_directory_path_str(), "/weights/a/b/c/d/e/abcdefghijk"); + } + + #[test] + pub fn get_directory_path_str_short_name() { + let directory = WeightFileBucketDirectory::from_object_hash("foo"); + assert_eq!(directory.get_directory_path_str(), "/weights/f/o/foo"); + } + + #[test] + pub fn get_object_hash() { + let hash = "abcdefghijk"; + let directory = WeightFileBucketDirectory::from_object_hash(hash); + assert_eq!(directory.get_object_hash(), hash); + } +} \ No newline at end of file diff --git a/crates/_types/buckets/src/public/weight_files/bucket_file_path.rs b/crates/_types/buckets/src/public/weight_files/bucket_file_path.rs new file mode 100644 index 0000000000..e1048a5494 --- /dev/null +++ b/crates/_types/buckets/src/public/weight_files/bucket_file_path.rs @@ -0,0 +1,142 @@ +use std::path::PathBuf; + +use crockford::crockford_entropy_lower; +use crate::public::public_path::PublicPath; + +const ORIGINAL_FILE_BASENAME : &str = "file.bin"; + +// TODO: Generate these from a macro. +use crate::public::weight_files::bucket_directory::WeightFileBucketDirectory; +/// The original user upload file. +/// It may have derivative files (down samples, crops, etc.) that live alongside it. +#[derive(Clone)] +pub struct WeightFileBucketPath { + directory: WeightFileBucketDirectory, + + filename: String, + full_object_path: String, + + optional_prefix: Option, + /// NB: Extension contains the leading period, eg. ".mp4" + optional_extension: Option, +} + +impl PublicPath for WeightFileBucketPath {} + +impl WeightFileBucketPath { + + pub fn generate_new(optional_prefix: Option<&str>, optional_extension: Option<&str>) -> Self { + let entropy = crockford_entropy_lower(32); + Self::from_object_hash(&entropy, optional_prefix, optional_extension) + } + + pub fn from_object_hash(hash: &str, optional_prefix: Option<&str>, optional_extension: Option<&str>) -> Self { + // TODO: Path construction could be cleaner. + let directory = WeightFileBucketDirectory::from_object_hash(hash); + + let filename = match (optional_prefix, optional_extension) { + (None, None) => ORIGINAL_FILE_BASENAME.to_string(), + (None, Some(ext)) => format!("{}{}", hash, ext), + (Some(pre), None) => format!("{}{}", pre, hash), + (Some(pre), Some(ext)) => format!("{}{}{}", pre, hash, ext), + }; + + let full_object_path = format!("{}/{}", directory.get_directory_path_str(), filename); + + Self { + directory, + filename, + full_object_path, + optional_prefix: optional_prefix.map(|p| p.to_string()), + optional_extension: optional_extension.map(|e| e.to_string()), + } + } + + pub fn get_full_object_path_str(&self) -> &str { + &self.full_object_path + } + + pub fn to_full_object_pathbuf(&self) -> PathBuf { + PathBuf::from(&self.full_object_path) + } + + pub fn get_directory(&self) -> &WeightFileBucketDirectory { + &self.directory + } + + pub fn get_object_hash(&self) -> &str { + &self.directory.get_object_hash() + } + + pub fn get_basename(&self) -> &str { + &self.filename + } +} + +#[cfg(test)] +mod tests { + use std::path::PathBuf; + + use crate::public::weight_files::bucket_file_path::WeightFileBucketPath; + mod with_prefix_and_extension { + use super::*; + + #[test] + pub fn generate_new_entropy() { + let file = WeightFileBucketPath::generate_new(Some("pre_"), Some(".mp4")); + assert_eq!(file.get_object_hash().len(), 32); + assert_eq!(file.get_object_hash().len(), 32); + assert_eq!(file.get_directory().get_object_hash().len(), 32); + } + + #[test] + pub fn get_full_object_path_str() { + let file = WeightFileBucketPath::from_object_hash("abcdefghijk", Some("pre_"), Some(".mp4")); + assert_eq!(file.get_full_object_path_str(), "/weights/a/b/c/d/e/abcdefghijk/pre_abcdefghijk.mp4"); + assert_eq!(file.get_basename(), "pre_abcdefghijk.mp4"); + } + } + + mod without_prefix_and_extension { + use super::*; + + #[test] + pub fn generate_new_entropy() { + let file = WeightFileBucketPath::generate_new(None, None); + assert_eq!(file.get_object_hash().len(), 32); + assert_eq!(file.get_directory().get_object_hash().len(), 32); + } + + #[test] + pub fn get_full_object_path_str() { + let file = WeightFileBucketPath::from_object_hash("abcdefghijk", None, None); + assert_eq!(file.get_full_object_path_str(), "/weights/a/b/c/d/e/abcdefghijk/file.bin"); + } + + #[test] + pub fn to_full_object_pathbuf() { + let file = WeightFileBucketPath::from_object_hash("abcdefghijk", None, None); + assert_eq!(file.to_full_object_pathbuf(), PathBuf::from("/weights/a/b/c/d/e/abcdefghijk/file.bin")); + } + + #[test] + pub fn get_full_object_path_str_short_name() { + let file = WeightFileBucketPath::from_object_hash("foo", None, None); + assert_eq!(file.get_full_object_path_str(), "/weights/f/o/foo/file.bin"); + } + + #[test] + pub fn get_full_object_path_str_starts_with_directory() { + let file = WeightFileBucketPath::from_object_hash("abcdefghijk", None, None); + let full_path = file.get_full_object_path_str(); + assert!(full_path.starts_with(file.get_directory().get_directory_path_str())) + } + + #[test] + pub fn get_object_hash() { + let hash = "abcdefghijk"; + let file = WeightFileBucketPath::from_object_hash(hash, None, None); + assert_eq!(file.get_object_hash(), hash); + } + } +} \ No newline at end of file diff --git a/crates/_types/buckets/src/public/weight_files/mod.rs b/crates/_types/buckets/src/public/weight_files/mod.rs new file mode 100644 index 0000000000..29c183a5c6 --- /dev/null +++ b/crates/_types/buckets/src/public/weight_files/mod.rs @@ -0,0 +1,2 @@ +pub mod bucket_directory; +pub mod bucket_file_path; \ No newline at end of file diff --git a/crates/cli/dev_database_seed/src/seeding/pythonex.py b/crates/cli/dev_database_seed/src/seeding/pythonex.py new file mode 100644 index 0000000000..19c31779f1 --- /dev/null +++ b/crates/cli/dev_database_seed/src/seeding/pythonex.py @@ -0,0 +1,33 @@ +from types import Optional + +class FileInfo: + size_in_bytes: int + mime_type: str + file_name: str + +class BucketDetails: + bucket_hash: str + maybe_bucket_name: Optional[str] + maybe_bucket_extension: Optional[str] + + +class MediaFileBucketDirectory: + object_hash: str + directory: str + optional_prefix: Optional[str] + optional_prefix_extension: Optional[str] + original_file_base_name: str + +class WeightsType: + directory: float + +class FileOperationManager: + def __init__(self, bucket,bucket_info:BucketDetails): + self.bucket = bucket + self.bucket_info = bucket_info + + def check_if_file_exists_in_db(self, file_token: str, callback) -> bool: + pass + + + diff --git a/crates/cli/dev_database_seed/src/seeding/seed_model_weights.rs b/crates/cli/dev_database_seed/src/seeding/seed_model_weights.rs index 72ab9badd3..9d97d4466b 100644 --- a/crates/cli/dev_database_seed/src/seeding/seed_model_weights.rs +++ b/crates/cli/dev_database_seed/src/seeding/seed_model_weights.rs @@ -3,7 +3,7 @@ use std::path::Path; use log::{ info, warn }; use sqlx::{ MySql, Pool }; -use buckets::{ public::{ media_files::bucket_file_path::MediaFileBucketPath, self }, private }; +use buckets::{ public::{ media_files::bucket_file_path::MediaFileBucketPath, self, weight_files::bucket_file_path::WeightFileBucketPath }, private }; use filesys::file_read_bytes::file_read_bytes; use filesys::file_size::file_size; @@ -213,7 +213,7 @@ async fn seed_file_to_bucket( .map(|extension| extension.to_str()) .flatten(); // we should just have this be file bucket path and then we can use a file descriptor to turn it into a specific type of path - let bucket_location = MediaFileBucketPath::generate_new( + let bucket_location = WeightFileBucketPath::generate_new( maybe_bucket_prefix, maybe_bucket_extension ); @@ -225,7 +225,7 @@ async fn seed_file_to_bucket( let bytes = file_read_bytes(weight_file_path)?; let mimetype = get_mimetype_for_bytes(&bytes).unwrap_or("application/octet-stream"); - info!("Uploading weights file to bucket path: {:?}", bucket_path); + info!("Copy this line here! Uploading weights file to bucket path: {:?}", bucket_path); let _r = bucket_clients.public.upload_file_with_content_type( &bucket_path, From 2c6a07659a12debcf3468c8e67cb6c9a3c0643bb Mon Sep 17 00:00:00 2001 From: Michael Chung Date: Fri, 15 Dec 2023 16:59:13 -0500 Subject: [PATCH 055/124] Ok weights now are properly linked. --- .../src/public/files/bucket_directory.rs | 0 .../buckets/src/public/files/descriptor.rs | 3 ++ crates/_types/buckets/src/public/files/mod.rs | 4 +++ .../src/public/files/web_file_manager.rs | 32 +++++++++++++++++++ 4 files changed, 39 insertions(+) delete mode 100644 crates/_types/buckets/src/public/files/bucket_directory.rs create mode 100644 crates/_types/buckets/src/public/files/descriptor.rs create mode 100644 crates/_types/buckets/src/public/files/mod.rs create mode 100644 crates/_types/buckets/src/public/files/web_file_manager.rs diff --git a/crates/_types/buckets/src/public/files/bucket_directory.rs b/crates/_types/buckets/src/public/files/bucket_directory.rs deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/crates/_types/buckets/src/public/files/descriptor.rs b/crates/_types/buckets/src/public/files/descriptor.rs new file mode 100644 index 0000000000..4b642780f7 --- /dev/null +++ b/crates/_types/buckets/src/public/files/descriptor.rs @@ -0,0 +1,3 @@ +pub trait descriptor { + fn my_method(&self); +} diff --git a/crates/_types/buckets/src/public/files/mod.rs b/crates/_types/buckets/src/public/files/mod.rs new file mode 100644 index 0000000000..b69a1e9b06 --- /dev/null +++ b/crates/_types/buckets/src/public/files/mod.rs @@ -0,0 +1,4 @@ +pub mod bucket_directory; +pub mod bucket_file_path; +pub mod web_file_manager; + diff --git a/crates/_types/buckets/src/public/files/web_file_manager.rs b/crates/_types/buckets/src/public/files/web_file_manager.rs new file mode 100644 index 0000000000..8ec339622c --- /dev/null +++ b/crates/_types/buckets/src/public/files/web_file_manager.rs @@ -0,0 +1,32 @@ + +pub struct FileBucketPath { + pub bucket_clients: BucketClients +} + +impl web_file_manager { + pub fn new(my_field: i32) -> Self { + web_file_manager { my_field } + } + + pub fn increment(&mut self) { + self.my_field += 1; + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_new() { + let my_class = web_file_manager::new(10); + assert_eq!(my_class.my_field, 10); + } + + #[test] + fn test_increment() { + let mut my_class = web_file_manager::new(10); + my_class.increment(); + assert_eq!(my_class.my_field, 11); + } +} \ No newline at end of file From c137e1ace39bdb3366a4f9af64dbd8b31545be38 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Fri, 15 Dec 2023 19:28:25 -0500 Subject: [PATCH 056/124] migration tool binary bootstrap --- .gitignore | 4 +++ Cargo.lock | 23 ++++++++++++++ Cargo.toml | 1 + crates/cli/migration-tool/Cargo.toml | 44 +++++++++++++++++++++++++++ crates/cli/migration-tool/src/main.rs | 23 ++++++++++++++ 5 files changed, 95 insertions(+) create mode 100644 crates/cli/migration-tool/Cargo.toml create mode 100644 crates/cli/migration-tool/src/main.rs diff --git a/.gitignore b/.gitignore index d9d031aab3..efa47b920d 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ .env .env-aichatbot-secrets .env-elasticsearch-secrets +.env-migration-tool-secrets .env-secrets _develop/tools/.secrets _develop/tools/db_secrets.toml @@ -17,6 +18,9 @@ secrets.toml secrets.yaml twitch_secrets.toml +# Old env secrets +.*-secrets + # New env secrets (per-app) *-secrets.env diff --git a/Cargo.lock b/Cargo.lock index 7af174d2be..a6a2c3ec3d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3480,6 +3480,29 @@ dependencies = [ "my-workspace-hack", ] +[[package]] +name = "migration-tool" +version = "0.0.1" +dependencies = [ + "buckets", + "clap", + "config", + "easyenv", + "enums", + "errors", + "log", + "my-workspace-hack", + "mysql_queries", + "serde", + "serde_derive", + "serde_json", + "sqlx", + "storyteller_root", + "strum", + "tokens", + "tokio", +] + [[package]] name = "mime" version = "0.3.17" diff --git a/Cargo.toml b/Cargo.toml index 411f131e53..e0a47f555a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ members = [ "crates/cli/elasticsearch-cli", "crates/cli/kubectl-pod-cleanup", "crates/cli/lru-delete-models", + "crates/cli/migration-tool", "crates/cli/scrape_test", # Shared libraries diff --git a/crates/cli/migration-tool/Cargo.toml b/crates/cli/migration-tool/Cargo.toml new file mode 100644 index 0000000000..2c7d4b065c --- /dev/null +++ b/crates/cli/migration-tool/Cargo.toml @@ -0,0 +1,44 @@ +[package] +name = "migration-tool" +edition = "2018" +version = "0.0.1" +authors = [ + "Brandon Thomas ", + "Brandon Thomas ", +] +publish = false + +[[bin]] +name = "migration-tool" +path = "src/main.rs" + +[dependencies] +# Internal +buckets = { path = "../../_types/buckets" } +config = { path = "../../lib/deprecated/config" } +easyenv = { path = "../../lib/easyenv" } +enums = { path = "../../_types/enums" } +errors = { path = "../../lib/errors" } +mysql_queries = { path = "../../lib/mysql_queries" } +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" } + +# External +clap = "4.4.8" +log = "0.4.14" +strum = { version = "0.25", features = ["derive"] } + +# Async + clients +tokio = { version = "1.34.0", features = ["macros"] } +sqlx = { version = "0.7.2", features = [ "mysql", "runtime-tokio", "tls-rustls", "chrono" ] } + +# Serialization +serde = "1.0.125" +serde_derive = "1.0.125" +serde_json = "1.0.108" + +[dev-dependencies] +# None yet diff --git a/crates/cli/migration-tool/src/main.rs b/crates/cli/migration-tool/src/main.rs new file mode 100644 index 0000000000..dd6af54df8 --- /dev/null +++ b/crates/cli/migration-tool/src/main.rs @@ -0,0 +1,23 @@ +//! migration-tool +//! +//! Migrate database records. +//! + + +use config::shared_constants::DEFAULT_RUST_LOG; +use errors::AnyhowResult; + +#[tokio::main] +pub async fn main() -> AnyhowResult<()> { + println!("migration-tool: migrate database records"); + + easyenv::init_all_with_default_logging(Some(DEFAULT_RUST_LOG)); + + // NB: This secrets file differs from the rest because we might actually want to cross + // development/production boundaries for migration. We don't want to pull in secrets + // from other sources. (Hopefully this isn't getting out of hand at this point.) + easyenv::from_filename(".env-migration-tool-secrets")?; + + + Ok(()) +} From 732dd27d0f853512161e8150aeb980e527475f49 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Fri, 15 Dec 2023 19:39:06 -0500 Subject: [PATCH 057/124] fix build errors; kebab-case all CLI apps --- Cargo.toml | 8 ++++---- .../{database_backup => database-backup}/Cargo.toml | 0 .../{database_backup => database-backup}/src/main.rs | 0 .../{database_cleanup => database-cleanup}/Cargo.toml | 0 .../{database_cleanup => database-cleanup}/src/main.rs | 0 .../Cargo.toml | 0 .../src/bucket_clients.rs | 0 .../src/cli_args.rs | 0 .../src/main.rs | 0 .../src/seeding/mod.rs | 0 .../src/seeding/model_weights.rs | 0 .../src/seeding/pythonex.py | 0 .../src/seeding/seed_media_files.rs | 0 .../src/seeding/seed_model_weights.rs | 10 ++++------ .../src/seeding/tts_tacotron2.rs | 0 .../src/seeding/users.rs | 0 .../src/seeding/voice_conversion.rs | 0 .../src/seeding/zero_shot_tts.rs | 0 .../Cargo.toml | 0 .../src/cli_args.rs | 0 .../src/main.rs | 0 21 files changed, 8 insertions(+), 10 deletions(-) rename crates/cli/{database_backup => database-backup}/Cargo.toml (100%) rename crates/cli/{database_backup => database-backup}/src/main.rs (100%) rename crates/cli/{database_cleanup => database-cleanup}/Cargo.toml (100%) rename crates/cli/{database_cleanup => database-cleanup}/src/main.rs (100%) rename crates/cli/{dev_database_seed => dev-database-seed}/Cargo.toml (100%) rename crates/cli/{dev_database_seed => dev-database-seed}/src/bucket_clients.rs (100%) rename crates/cli/{dev_database_seed => dev-database-seed}/src/cli_args.rs (100%) rename crates/cli/{dev_database_seed => dev-database-seed}/src/main.rs (100%) rename crates/cli/{dev_database_seed => dev-database-seed}/src/seeding/mod.rs (100%) rename crates/cli/{dev_database_seed => dev-database-seed}/src/seeding/model_weights.rs (100%) rename crates/cli/{dev_database_seed => dev-database-seed}/src/seeding/pythonex.py (100%) rename crates/cli/{dev_database_seed => dev-database-seed}/src/seeding/seed_media_files.rs (100%) rename crates/cli/{dev_database_seed => dev-database-seed}/src/seeding/seed_model_weights.rs (96%) rename crates/cli/{dev_database_seed => dev-database-seed}/src/seeding/tts_tacotron2.rs (100%) rename crates/cli/{dev_database_seed => dev-database-seed}/src/seeding/users.rs (100%) rename crates/cli/{dev_database_seed => dev-database-seed}/src/seeding/voice_conversion.rs (100%) rename crates/cli/{dev_database_seed => dev-database-seed}/src/seeding/zero_shot_tts.rs (100%) rename crates/cli/{dev_upload_media_file => dev-upload-media-file}/Cargo.toml (100%) rename crates/cli/{dev_upload_media_file => dev-upload-media-file}/src/cli_args.rs (100%) rename crates/cli/{dev_upload_media_file => dev-upload-media-file}/src/main.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index e0a47f555a..78728f6407 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,10 +10,10 @@ members = [ "crates/_types/tokens", # CLI tools for operations, etc. - "crates/cli/database_backup", - "crates/cli/database_cleanup", - "crates/cli/dev_database_seed", - "crates/cli/dev_upload_media_file", + "crates/cli/database-backup", + "crates/cli/database-cleanup", + "crates/cli/dev-database-seed", + "crates/cli/dev-upload-media-file", "crates/cli/elasticsearch-cli", "crates/cli/kubectl-pod-cleanup", "crates/cli/lru-delete-models", diff --git a/crates/cli/database_backup/Cargo.toml b/crates/cli/database-backup/Cargo.toml similarity index 100% rename from crates/cli/database_backup/Cargo.toml rename to crates/cli/database-backup/Cargo.toml diff --git a/crates/cli/database_backup/src/main.rs b/crates/cli/database-backup/src/main.rs similarity index 100% rename from crates/cli/database_backup/src/main.rs rename to crates/cli/database-backup/src/main.rs diff --git a/crates/cli/database_cleanup/Cargo.toml b/crates/cli/database-cleanup/Cargo.toml similarity index 100% rename from crates/cli/database_cleanup/Cargo.toml rename to crates/cli/database-cleanup/Cargo.toml diff --git a/crates/cli/database_cleanup/src/main.rs b/crates/cli/database-cleanup/src/main.rs similarity index 100% rename from crates/cli/database_cleanup/src/main.rs rename to crates/cli/database-cleanup/src/main.rs diff --git a/crates/cli/dev_database_seed/Cargo.toml b/crates/cli/dev-database-seed/Cargo.toml similarity index 100% rename from crates/cli/dev_database_seed/Cargo.toml rename to crates/cli/dev-database-seed/Cargo.toml diff --git a/crates/cli/dev_database_seed/src/bucket_clients.rs b/crates/cli/dev-database-seed/src/bucket_clients.rs similarity index 100% rename from crates/cli/dev_database_seed/src/bucket_clients.rs rename to crates/cli/dev-database-seed/src/bucket_clients.rs diff --git a/crates/cli/dev_database_seed/src/cli_args.rs b/crates/cli/dev-database-seed/src/cli_args.rs similarity index 100% rename from crates/cli/dev_database_seed/src/cli_args.rs rename to crates/cli/dev-database-seed/src/cli_args.rs diff --git a/crates/cli/dev_database_seed/src/main.rs b/crates/cli/dev-database-seed/src/main.rs similarity index 100% rename from crates/cli/dev_database_seed/src/main.rs rename to crates/cli/dev-database-seed/src/main.rs diff --git a/crates/cli/dev_database_seed/src/seeding/mod.rs b/crates/cli/dev-database-seed/src/seeding/mod.rs similarity index 100% rename from crates/cli/dev_database_seed/src/seeding/mod.rs rename to crates/cli/dev-database-seed/src/seeding/mod.rs diff --git a/crates/cli/dev_database_seed/src/seeding/model_weights.rs b/crates/cli/dev-database-seed/src/seeding/model_weights.rs similarity index 100% rename from crates/cli/dev_database_seed/src/seeding/model_weights.rs rename to crates/cli/dev-database-seed/src/seeding/model_weights.rs diff --git a/crates/cli/dev_database_seed/src/seeding/pythonex.py b/crates/cli/dev-database-seed/src/seeding/pythonex.py similarity index 100% rename from crates/cli/dev_database_seed/src/seeding/pythonex.py rename to crates/cli/dev-database-seed/src/seeding/pythonex.py diff --git a/crates/cli/dev_database_seed/src/seeding/seed_media_files.rs b/crates/cli/dev-database-seed/src/seeding/seed_media_files.rs similarity index 100% rename from crates/cli/dev_database_seed/src/seeding/seed_media_files.rs rename to crates/cli/dev-database-seed/src/seeding/seed_media_files.rs diff --git a/crates/cli/dev_database_seed/src/seeding/seed_model_weights.rs b/crates/cli/dev-database-seed/src/seeding/seed_model_weights.rs similarity index 96% rename from crates/cli/dev_database_seed/src/seeding/seed_model_weights.rs rename to crates/cli/dev-database-seed/src/seeding/seed_model_weights.rs index 66f222c408..5af2266431 100644 --- a/crates/cli/dev_database_seed/src/seeding/seed_model_weights.rs +++ b/crates/cli/dev-database-seed/src/seeding/seed_model_weights.rs @@ -1,12 +1,10 @@ use std::path::Path; -use log::{ info, warn }; -use sqlx::{ MySql, Pool }; +use log::{info, warn}; +use rand::Rng; +use sqlx::{MySql, Pool}; -use buckets::{ public::{ media_files::bucket_file_path::MediaFileBucketPath, self, weight_files::bucket_file_path::WeightFileBucketPath }, private }; - - -use buckets::public::media_files::bucket_file_path::MediaFileBucketPath; +use buckets::public::weight_files::bucket_file_path::WeightFileBucketPath; use enums::{ by_table::model_weights::{weights_category::WeightsCategory, weights_types::WeightsType}, common::visibility::Visibility, diff --git a/crates/cli/dev_database_seed/src/seeding/tts_tacotron2.rs b/crates/cli/dev-database-seed/src/seeding/tts_tacotron2.rs similarity index 100% rename from crates/cli/dev_database_seed/src/seeding/tts_tacotron2.rs rename to crates/cli/dev-database-seed/src/seeding/tts_tacotron2.rs diff --git a/crates/cli/dev_database_seed/src/seeding/users.rs b/crates/cli/dev-database-seed/src/seeding/users.rs similarity index 100% rename from crates/cli/dev_database_seed/src/seeding/users.rs rename to crates/cli/dev-database-seed/src/seeding/users.rs diff --git a/crates/cli/dev_database_seed/src/seeding/voice_conversion.rs b/crates/cli/dev-database-seed/src/seeding/voice_conversion.rs similarity index 100% rename from crates/cli/dev_database_seed/src/seeding/voice_conversion.rs rename to crates/cli/dev-database-seed/src/seeding/voice_conversion.rs diff --git a/crates/cli/dev_database_seed/src/seeding/zero_shot_tts.rs b/crates/cli/dev-database-seed/src/seeding/zero_shot_tts.rs similarity index 100% rename from crates/cli/dev_database_seed/src/seeding/zero_shot_tts.rs rename to crates/cli/dev-database-seed/src/seeding/zero_shot_tts.rs diff --git a/crates/cli/dev_upload_media_file/Cargo.toml b/crates/cli/dev-upload-media-file/Cargo.toml similarity index 100% rename from crates/cli/dev_upload_media_file/Cargo.toml rename to crates/cli/dev-upload-media-file/Cargo.toml diff --git a/crates/cli/dev_upload_media_file/src/cli_args.rs b/crates/cli/dev-upload-media-file/src/cli_args.rs similarity index 100% rename from crates/cli/dev_upload_media_file/src/cli_args.rs rename to crates/cli/dev-upload-media-file/src/cli_args.rs diff --git a/crates/cli/dev_upload_media_file/src/main.rs b/crates/cli/dev-upload-media-file/src/main.rs similarity index 100% rename from crates/cli/dev_upload_media_file/src/main.rs rename to crates/cli/dev-upload-media-file/src/main.rs From 05789802056c79ed06988f499d301e239b15379a Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Sat, 16 Dec 2023 23:26:16 -0500 Subject: [PATCH 058/124] re-home nessu's models (per vegito) --- _sql/actions/tts_models.sql | 6 ++++++ _sql/actions/voice_conversion_models.sql | 3 +++ .../cli/dev-database-seed/src/seeding/seed_model_weights.rs | 3 +-- 3 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 _sql/actions/tts_models.sql diff --git a/_sql/actions/tts_models.sql b/_sql/actions/tts_models.sql new file mode 100644 index 0000000000..eadec00f93 --- /dev/null +++ b/_sql/actions/tts_models.sql @@ -0,0 +1,6 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +-- Re-home Nessu's models +update tts_models set creator_user_token = "user_7z1h6sykg4r62" where creator_user_token = "U:C00NRSW1AE8T4" limit 5; diff --git a/_sql/actions/voice_conversion_models.sql b/_sql/actions/voice_conversion_models.sql index 7f97f2da68..ddff34378a 100644 --- a/_sql/actions/voice_conversion_models.sql +++ b/_sql/actions/voice_conversion_models.sql @@ -13,6 +13,9 @@ where token IN ( 'vcm_502wkt2pca3y' ); +-- Re-home Nessu's models +update voice_conversion_models set creator_user_token = "user_7z1h6sykg4r62" where creator_user_token = "U:C00NRSW1AE8T4" limit 5; + -- Remove broken models update voice_conversion_models set diff --git a/crates/cli/dev-database-seed/src/seeding/seed_model_weights.rs b/crates/cli/dev-database-seed/src/seeding/seed_model_weights.rs index 5af2266431..566624561a 100644 --- a/crates/cli/dev-database-seed/src/seeding/seed_model_weights.rs +++ b/crates/cli/dev-database-seed/src/seeding/seed_model_weights.rs @@ -17,8 +17,7 @@ use hashing::sha256::sha256_hash_file::sha256_hash_file; use mimetypes::mimetype_for_bytes::get_mimetype_for_bytes; use mysql_queries::queries::model_weights::create_weight::{ create_weight, - CreateModelWeightsArgs - , + CreateModelWeightsArgs, }; use storyteller_root::get_seed_tool_data_root; use tokens::tokens::model_weights::ModelWeightToken; From 7755a5683b136511f8bd191bec73c8750ddb550d Mon Sep 17 00:00:00 2001 From: Michael Chung Date: Mon, 18 Dec 2023 09:26:12 -0500 Subject: [PATCH 059/124] Working on file descriptors though gotta learn some rust things, quickly for boiler plate. --- .../buckets/src/public/files/descriptor.rs | 3 - .../src/public/files/file_descriptor.rs | 55 +++++++++++ .../src/public/files/media_descriptor.rs | 0 crates/_types/buckets/src/public/files/mod.rs | 3 +- .../src/public/files/web_file_manager.rs | 93 +++++++++++++++---- crates/_types/buckets/src/public/mod.rs | 3 +- .../dev_database_seed/src/seeding/pythonex.py | 33 ------- .../src/seeding/seed_model_weights.rs | 2 +- 8 files changed, 133 insertions(+), 59 deletions(-) delete mode 100644 crates/_types/buckets/src/public/files/descriptor.rs create mode 100644 crates/_types/buckets/src/public/files/file_descriptor.rs delete mode 100644 crates/_types/buckets/src/public/files/media_descriptor.rs delete mode 100644 crates/cli/dev_database_seed/src/seeding/pythonex.py diff --git a/crates/_types/buckets/src/public/files/descriptor.rs b/crates/_types/buckets/src/public/files/descriptor.rs deleted file mode 100644 index 4b642780f7..0000000000 --- a/crates/_types/buckets/src/public/files/descriptor.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub trait descriptor { - fn my_method(&self); -} diff --git a/crates/_types/buckets/src/public/files/file_descriptor.rs b/crates/_types/buckets/src/public/files/file_descriptor.rs new file mode 100644 index 0000000000..770bb5d0d7 --- /dev/null +++ b/crates/_types/buckets/src/public/files/file_descriptor.rs @@ -0,0 +1,55 @@ +// Describes the file and how it will be saved to GCBucket +#[derive(Clone)] +pub struct FileDescriptorBucketDirectory { + object_hash: String, + directory: String, +} + +// where the file should be stored based off the descriptor +const WEIGHT_FILE_DIRECTORY: &str = "/weights"; +pub trait FileDescriptor { + // this will be the type of file + // e.g .safetensors .bin .jpg + fn get_suffix(&self)->String { + return ".bin".to_string(); + } + // This will be the prefix of the media type or the weights type. + // name of the weights or the name of the media type + // vall-e_prompt, loRA, sd15, sdxl + fn get_prefix(&self)->String { + return "fake_u".to_string(); + } + // This will be the token generated from the database record. + fn set_hash(&mut self, hash: String); +} + +// TODO FIX +// #[cfg(test)] +// mod tests { +// use crate::public::weight_files::bucket_directory::WeightFileBucketDirectory; + +// #[test] +// pub fn generate_new_entropy() { +// let directory = WeightFileBucketDirectory::generate_new(); +// assert_eq!(directory.get_object_hash().len(), 32); +// } + +// #[test] +// pub fn get_directory_path_str() { +// let directory = WeightFileBucketDirectory::from_object_hash("abcdefghijk"); +// assert_eq!(directory.get_directory_path_str(), "/weights/a/b/c/d/e/abcdefghijk"); +// } + +// #[test] +// pub fn get_directory_path_str_short_name() { +// let directory = WeightFileBucketDirectory::from_object_hash("foo"); +// assert_eq!(directory.get_directory_path_str(), "/weights/f/o/foo"); +// } + +// #[test] +// pub fn get_object_hash() { +// let hash = "abcdefghijk"; +// let directory = WeightFileBucketDirectory::from_object_hash(hash); +// assert_eq!(directory.get_object_hash(), hash); +// } +// } \ No newline at end of file diff --git a/crates/_types/buckets/src/public/files/media_descriptor.rs b/crates/_types/buckets/src/public/files/media_descriptor.rs deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/crates/_types/buckets/src/public/files/mod.rs b/crates/_types/buckets/src/public/files/mod.rs index b69a1e9b06..877a504b42 100644 --- a/crates/_types/buckets/src/public/files/mod.rs +++ b/crates/_types/buckets/src/public/files/mod.rs @@ -1,4 +1,3 @@ -pub mod bucket_directory; -pub mod bucket_file_path; pub mod web_file_manager; +pub mod file_descriptor; diff --git a/crates/_types/buckets/src/public/files/web_file_manager.rs b/crates/_types/buckets/src/public/files/web_file_manager.rs index 8ec339622c..67dac90909 100644 --- a/crates/_types/buckets/src/public/files/web_file_manager.rs +++ b/crates/_types/buckets/src/public/files/web_file_manager.rs @@ -1,32 +1,87 @@ +// use crockford::crockford_entropy_lower; +// use crate::util::hashed_directory_path_long_string::hashed_directory_path_long_string; +// use cloud_storage::bucket_client::BucketClient; +use crate::public::files::file_descriptor::FileDescriptor; -pub struct FileBucketPath { - pub bucket_clients: BucketClients +pub struct WeightsDescriptor { + pub hash: String, + pub prefix: String, + pub suffix: String } -impl web_file_manager { - pub fn new(my_field: i32) -> Self { - web_file_manager { my_field } +impl FileDescriptor for WeightsDescriptor { + fn get_suffix(&self)->String { + return self.suffix.clone(); } - - pub fn increment(&mut self) { - self.my_field += 1; + // This will be the prefix of the media type or the weights type. + // name of the weights or the name of the media type + // vall-e_prompt, loRA, sd15, sdxl + fn get_prefix(&self)->String { + return self.prefix.clone(); + } + // This will be the token generated from the database record. + fn set_hash(&mut self, hash: String) { + self.hash = hash; } } +pub struct FileMetaData { + pub file_size_bytes: u64, + pub sha256_checksum: String, + pub mimetype: String +} + +// impl FileDescriptor for WeightsDescriptor { +// fn get_suffix(&self)->String { +// return ".bin".to_string(); +// } +// // This will be the prefix of the media type or the weights type. +// // name of the weights or the name of the media type +// // vall-e_prompt, loRA, sd15, sdxl +// fn get_prefix(&self)->String { +// return "fake_u".to_string(); +// } +// } + +// pub struct WebFileManager { +// pub file_descriptor: FileDescriptor +// } + + +// handles download as well. +struct WebFileManager { + // bucket_client: BucketClient, + file_descriptor: FileDescriptor +} +impl WebFileManager { + fn new(file_descriptor: dyn FileDescriptor) -> WebFileManager { + WebFileManager { + // bucket_client: bucket_client, + file_descriptor: file_descriptor + } + } + pub fn something() { + + } +} + + +// take in system file path to upload. +// take in system file path to download to. + +// should be able to take prefix suffix and entrpy to generate a file descriptor + +// should return this once properly uploaded. +// let file_size_bytes = file_size(weight_file_path.clone())?; +// let sha256_checksum = sha256_hash_file(weight_file_path.clone())?; + #[cfg(test)] mod tests { - use super::*; - + //use crate::public::files::file_descriptor::{FileDescriptor}; + //use super::WebFileManager; #[test] - fn test_new() { - let my_class = web_file_manager::new(10); - assert_eq!(my_class.my_field, 10); + fn test_web_file_manager() { + } - #[test] - fn test_increment() { - let mut my_class = web_file_manager::new(10); - my_class.increment(); - assert_eq!(my_class.my_field, 11); - } } \ No newline at end of file diff --git a/crates/_types/buckets/src/public/mod.rs b/crates/_types/buckets/src/public/mod.rs index 97aca68159..c3f3f18b09 100644 --- a/crates/_types/buckets/src/public/mod.rs +++ b/crates/_types/buckets/src/public/mod.rs @@ -3,4 +3,5 @@ pub mod media_uploads; pub mod public_path; pub mod voice_conversion_results; pub mod weight_uploads; -pub mod weight_files; \ No newline at end of file +pub mod weight_files; +pub mod files; \ No newline at end of file diff --git a/crates/cli/dev_database_seed/src/seeding/pythonex.py b/crates/cli/dev_database_seed/src/seeding/pythonex.py deleted file mode 100644 index 19c31779f1..0000000000 --- a/crates/cli/dev_database_seed/src/seeding/pythonex.py +++ /dev/null @@ -1,33 +0,0 @@ -from types import Optional - -class FileInfo: - size_in_bytes: int - mime_type: str - file_name: str - -class BucketDetails: - bucket_hash: str - maybe_bucket_name: Optional[str] - maybe_bucket_extension: Optional[str] - - -class MediaFileBucketDirectory: - object_hash: str - directory: str - optional_prefix: Optional[str] - optional_prefix_extension: Optional[str] - original_file_base_name: str - -class WeightsType: - directory: float - -class FileOperationManager: - def __init__(self, bucket,bucket_info:BucketDetails): - self.bucket = bucket - self.bucket_info = bucket_info - - def check_if_file_exists_in_db(self, file_token: str, callback) -> bool: - pass - - - diff --git a/crates/cli/dev_database_seed/src/seeding/seed_model_weights.rs b/crates/cli/dev_database_seed/src/seeding/seed_model_weights.rs index 9d97d4466b..82e88e1881 100644 --- a/crates/cli/dev_database_seed/src/seeding/seed_model_weights.rs +++ b/crates/cli/dev_database_seed/src/seeding/seed_model_weights.rs @@ -213,7 +213,7 @@ async fn seed_file_to_bucket( .map(|extension| extension.to_str()) .flatten(); // we should just have this be file bucket path and then we can use a file descriptor to turn it into a specific type of path - let bucket_location = WeightFileBucketPath::generate_new( + let bucket_location: WeightFileBucketPath = WeightFileBucketPath::generate_new( maybe_bucket_prefix, maybe_bucket_extension ); From 25b90c07ce4ed4382d4f8d1f750e3b65b692b6dc Mon Sep 17 00:00:00 2001 From: saltacc Date: Mon, 18 Dec 2023 15:49:55 -0800 Subject: [PATCH 060/124] add model downloading --- .../rerender_a_video/download_model_file.rs | 10 +++++----- .../job/job_types/videofilter/rerender_a_video/mod.rs | 3 +-- .../videofilter/rerender_a_video/process_job.rs | 3 +-- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/download_model_file.rs b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/download_model_file.rs index 42e4298f77..ee848d3361 100644 --- a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/download_model_file.rs +++ b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/download_model_file.rs @@ -27,7 +27,7 @@ pub async fn download_model_file( ) -> Result { let bucket_object_path; - + let model_filename; match model_record { Some(model_record) => { let model_bucket_path = @@ -36,18 +36,18 @@ pub async fn download_model_file( model_record.maybe_private_bucket_prefix.as_deref(), model_record.maybe_private_bucket_extension.as_deref(), ); + model_filename = model_record.private_bucket_hash.clone() + ".".to_owned() + model_record.maybe_private_bucket_extension.as_deref().unwrap_or("bin"); bucket_object_path = model_bucket_path.to_full_object_pathbuf(); } None => { return Err(ProcessSingleJobError::from_anyhow_error( anyhow!("could not find model file"))) } - } - - let downloaded_filesystem_path = work_temp_dir.path().join("video.mp4"); + }; + let downloaded_filesystem_path = work_temp_dir.path().join(model_filename); maybe_download_file_from_bucket(MaybeDownloadArgs { - name_or_description_of_file: "video file", + name_or_description_of_file: "model file", final_filesystem_file_path: &downloaded_filesystem_path, bucket_object_path: &bucket_object_path, bucket_client: public_bucket_client, diff --git a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/mod.rs b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/mod.rs index 6b30de9473..dc00dc3412 100644 --- a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/mod.rs +++ b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/mod.rs @@ -4,5 +4,4 @@ mod download_video_file; mod rerender_inference_command; pub(crate) mod rerender_dependencies; mod categorize_error; -mod download_model_file; -mod download_model_file; +mod download_model_file; \ No newline at end of file diff --git a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/process_job.rs b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/process_job.rs index 3cb8598978..cce8a0b8b5 100644 --- a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/process_job.rs +++ b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/process_job.rs @@ -25,7 +25,6 @@ use crate::job::job_types::videofilter::rerender_a_video::download_video_file::d use crate::job::job_types::videofilter::rerender_a_video::rerender_inference_command::InferenceArgs; use crate::job::job_types::videofilter::rerender_a_video::validate_job::validate_job; use crate::job_dependencies::JobDependencies; -use crate::util::maybe_download_file_from_bucket::{maybe_download_file_from_bucket, MaybeDownloadArgs}; /// The maximum that either width or height can be const MAX_DIMENSION : u32 = 1500; @@ -276,7 +275,7 @@ pub async fn process_job(args: RerenderProcessJobArgs<'_>) -> Result Date: Mon, 18 Dec 2023 21:08:43 -0500 Subject: [PATCH 061/124] Seed Model weights fix --- .../src/seeding/seed_model_weights.rs | 65 ++++++++----------- 1 file changed, 28 insertions(+), 37 deletions(-) diff --git a/crates/cli/dev-database-seed/src/seeding/seed_model_weights.rs b/crates/cli/dev-database-seed/src/seeding/seed_model_weights.rs index 566624561a..e479f275da 100644 --- a/crates/cli/dev-database-seed/src/seeding/seed_model_weights.rs +++ b/crates/cli/dev-database-seed/src/seeding/seed_model_weights.rs @@ -1,5 +1,5 @@ -use std::path::Path; - +use std::{path::Path, string}; +use errors::{anyhow, AnyhowResult}; use log::{info, warn}; use rand::Rng; use sqlx::{MySql, Pool}; @@ -9,7 +9,6 @@ use enums::{ by_table::model_weights::{weights_category::WeightsCategory, weights_types::WeightsType}, common::visibility::Visibility, }; -use errors::AnyhowResult; use filesys::file_read_bytes::file_read_bytes; use filesys::file_size::file_size; use filesys::path_to_string::path_to_string; @@ -94,9 +93,9 @@ pub async fn seed_weights_files( let original_download_url = "https://example.com/model.safetensors"; let thumbnail_token = format!("{}", n); - let public_bucket_hash: String = weights_file_token.to_string(); - let public_bucket_prefix = weights_type.to_str(); - let public_bucket_extension = weights_category.to_str(); + // let public_bucket_hash: String = weights_file_token.to_string(); + // let public_bucket_prefix = weights_type.to_string(); + // let public_bucket_extension = weights_category.to_string(); let cached_user_ratings_total_count = n.clone(); let cached_user_ratings_positive_count = n.clone(); @@ -111,7 +110,7 @@ pub async fn seed_weights_files( let file_size_bytes = file_size(weight_file_path.clone())?; let sha256_checksum = sha256_hash_file(weight_file_path.clone())?; - let result = seed_model( + let bucket_details = seed_model( &mysql_pool, &model_weight_token, &user_token, @@ -119,6 +118,11 @@ pub async fn seed_weights_files( &weight_file_path, maybe_bucket_clients ).await; + let bucket_details_data = bucket_details.unwrap(); + + let bucket_hash = bucket_details_data.bucket_hash; + let maybe_bucket_prefix = bucket_details_data.maybe_bucket_prefix.as_deref().unwrap(); + let maybe_bucket_extension = bucket_details_data.maybe_bucket_extension.as_deref().unwrap(); let create_model_weights_args = CreateModelWeightsArgs { token: &model_weight_token, @@ -136,9 +140,9 @@ pub async fn seed_weights_files( original_filename: Some(original_filename.to_string()), file_size_bytes: file_size_bytes as i32, // Assuming the file size is 0 file_checksum_sha2: sha256_checksum.to_string(), // Assuming the file checksum is an empty string - private_bucket_hash: public_bucket_hash, - maybe_private_bucket_prefix: Some(public_bucket_prefix.to_string()), - maybe_private_bucket_extension: Some(public_bucket_extension.to_string()), + private_bucket_hash: bucket_hash, + maybe_private_bucket_prefix: Some(maybe_bucket_prefix.to_string()), + maybe_private_bucket_extension: Some(maybe_bucket_extension.to_string()), cached_user_ratings_total_count, cached_user_ratings_positive_count, cached_user_ratings_negative_count, @@ -149,24 +153,15 @@ pub async fn seed_weights_files( create_weight(create_model_weights_args).await?; - match result { - Ok(_) => info!("Seeded {:?}", weight_file_path), - Err(err) => - warn!( - r#" - Could not seed media file {} , {:?} : {:?} - (No worries: if there's a duplicate key error, we probably already - seeded the media file on a previous invocation!) - "#, - model_weight_token, - subdirectory_path, - err - ), - } + + info!("Seeded {:?}", weight_file_path) + } Ok(()) } + +#[derive(Clone)] struct BucketDetails { bucket_hash: String, maybe_bucket_prefix: Option, @@ -180,30 +175,26 @@ async fn seed_model( weight_type: WeightsType, weight_file_path: &Path, maybe_bucket_clients: Option<&BucketClients> -) -> AnyhowResult<()> { +) -> AnyhowResult { info!("Seeding Media file {:?} ...", weight_file_path); // mutable variables - let mut bucket_hash = "NOT_UPLOADED_BY_SEED_TOOL".to_string(); - let mut maybe_bucket_prefix = ""; - let mut maybe_bucket_extension = ""; - if let Some(bucket_clients) = maybe_bucket_clients { - let bucket_details = seed_file_to_bucket(weight_file_path, bucket_clients).await?; - bucket_hash = bucket_details.bucket_hash; - maybe_bucket_prefix = bucket_details.maybe_bucket_prefix.as_deref().unwrap(); - maybe_bucket_extension = bucket_details.maybe_bucket_extension.as_deref().unwrap(); + let bucket_details = seed_file_to_bucket(weight_file_path, bucket_clients,weight_type).await?; + return Ok(bucket_details); } - - Ok(()) + Err(anyhow!("No bucket clients provided!")) + } async fn seed_file_to_bucket( weight_file_path: &Path, - bucket_clients: &BucketClients + bucket_clients: &BucketClients, + weight_type: WeightsType, ) -> AnyhowResult { info!("Uploading weights file {:?} ...", weight_file_path); - let maybe_bucket_prefix = Some("fakeyou_"); + let maybe_bucket_prefix = Some(format!("{}_",weight_type.to_str())); + let maybe_bucket_prefix = maybe_bucket_prefix.as_deref(); let maybe_bucket_extension = weight_file_path .extension() From b12402805597f23e1de375323bbaded7c8ab6c74 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Sun, 17 Dec 2023 00:43:37 -0500 Subject: [PATCH 062/124] Migration tool for voice conversion models --- crates/cli/migration-tool/src/deps.rs | 6 + crates/cli/migration-tool/src/main.rs | 26 ++ .../cli/migration-tool/src/migrations/mod.rs | 1 + .../voice_conversion_to_weights/migrate.rs | 34 +++ .../voice_conversion_to_weights/mod.rs | 1 + .../filesys/src/is_filesystem_full_error.rs | 2 +- .../filesys/src/rename_across_devices.rs | 2 +- ...le_voice_conversion_models_using_cursor.rs | 249 ++++++++++++++++++ .../queries/voice_conversion/models/mod.rs | 1 + 9 files changed, 320 insertions(+), 2 deletions(-) create mode 100644 crates/cli/migration-tool/src/deps.rs create mode 100644 crates/cli/migration-tool/src/migrations/mod.rs create mode 100644 crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/migrate.rs create mode 100644 crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/mod.rs create mode 100644 crates/lib/mysql_queries/src/queries/voice_conversion/models/list_whole_voice_conversion_models_using_cursor.rs diff --git a/crates/cli/migration-tool/src/deps.rs b/crates/cli/migration-tool/src/deps.rs new file mode 100644 index 0000000000..b86d9cc35f --- /dev/null +++ b/crates/cli/migration-tool/src/deps.rs @@ -0,0 +1,6 @@ +use sqlx::{MySql, Pool}; + +pub struct Deps { + pub mysql_development : Pool, + pub mysql_production : Pool, +} diff --git a/crates/cli/migration-tool/src/main.rs b/crates/cli/migration-tool/src/main.rs index dd6af54df8..4e94ccd1c0 100644 --- a/crates/cli/migration-tool/src/main.rs +++ b/crates/cli/migration-tool/src/main.rs @@ -4,9 +4,19 @@ //! +use log::info; +use sqlx::{MySql, Pool}; +use sqlx::mysql::MySqlPoolOptions; + use config::shared_constants::DEFAULT_RUST_LOG; use errors::AnyhowResult; +use crate::deps::Deps; +use crate::migrations::voice_conversion_to_weights::migrate::migrate_voice_conversion_to_weights; + +pub mod deps; +pub mod migrations; + #[tokio::main] pub async fn main() -> AnyhowResult<()> { println!("migration-tool: migrate database records"); @@ -18,6 +28,22 @@ pub async fn main() -> AnyhowResult<()> { // from other sources. (Hopefully this isn't getting out of hand at this point.) easyenv::from_filename(".env-migration-tool-secrets")?; + let deps = Deps { + mysql_development: get_mysql("MYSQL_DEVELOPMENT_URL").await?, + mysql_production: get_mysql("MYSQL_PRODUCTION_URL").await?, + }; + + migrate_voice_conversion_to_weights(&deps).await?; Ok(()) } +async fn get_mysql(env_var_name: &str) -> AnyhowResult> { + info!("Connecting to MySQL {env_var_name}..."); + + let pool = MySqlPoolOptions::new() + .max_connections(easyenv::get_env_num("MYSQL_MAX_CONNECTIONS", 3)?) + .connect(&easyenv::get_env_string_required(env_var_name)?) + .await?; + + Ok(pool) +} diff --git a/crates/cli/migration-tool/src/migrations/mod.rs b/crates/cli/migration-tool/src/migrations/mod.rs new file mode 100644 index 0000000000..c0183ac4c9 --- /dev/null +++ b/crates/cli/migration-tool/src/migrations/mod.rs @@ -0,0 +1 @@ +pub mod voice_conversion_to_weights; \ No newline at end of file diff --git a/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/migrate.rs b/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/migrate.rs new file mode 100644 index 0000000000..9513ad2c0b --- /dev/null +++ b/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/migrate.rs @@ -0,0 +1,34 @@ +use std::thread; +use std::time::Duration; +use errors::AnyhowResult; +use mysql_queries::queries::voice_conversion::models::list_whole_voice_conversion_models_using_cursor::list_whole_voice_conversion_models_using_cursor; +use crate::deps::Deps; + +const PAGE_SIZE: u64 = 10; + +pub async fn migrate_voice_conversion_to_weights(deps: &Deps) -> AnyhowResult<()> { + + let mut cursor = 0; + + loop { + + let results + = list_whole_voice_conversion_models_using_cursor(&deps.mysql_production, PAGE_SIZE, cursor).await?; + + if results.is_empty() { + break; + } + + for result in results.iter() { + println!("result: {:?}", result); + } + + if let Some(last_id) = results.last().map(|result| result.id) { + cursor = last_id as u64; + } + + thread::sleep(Duration::from_secs(2)); + } + + Ok(()) +} diff --git a/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/mod.rs b/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/mod.rs new file mode 100644 index 0000000000..64da02492a --- /dev/null +++ b/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/mod.rs @@ -0,0 +1 @@ +pub mod migrate; \ No newline at end of file diff --git a/crates/lib/files/filesys/src/is_filesystem_full_error.rs b/crates/lib/files/filesys/src/is_filesystem_full_error.rs index f4f8301523..fdbc459e79 100644 --- a/crates/lib/files/filesys/src/is_filesystem_full_error.rs +++ b/crates/lib/files/filesys/src/is_filesystem_full_error.rs @@ -1,7 +1,7 @@ // Nearly a third of `ErrorKind` is nightly rust, so we're going to have to match on // unix error codes until the rest of the ErrorKind enum variants are stable. -// The error codes are maintained in sys/unix/mod.rs - decode_error_kind(i32) +// The error codes are maintained in sys/unix/voice_conversion_to_weights - decode_error_kind(i32) const E_FILESYSTEM_QUOTA_EXCEEDED : i32 = 122; // pub const EDQUOT: ::c_int = 122; const E_STORAGE_FULL : i32 = 28; // pub const ENOSPC: ::c_int = 28; diff --git a/crates/lib/files/filesys/src/rename_across_devices.rs b/crates/lib/files/filesys/src/rename_across_devices.rs index 25b9e05a31..13c53b84ed 100644 --- a/crates/lib/files/filesys/src/rename_across_devices.rs +++ b/crates/lib/files/filesys/src/rename_across_devices.rs @@ -43,7 +43,7 @@ pub fn rename_across_devices, Q: AsRef>(from: P, to: Q) -> // Nearly a third of `ErrorKind` is nightly rust, so we're going to have to match on // unix error codes until the rest of the ErrorKind enum variants are stable. - // The error codes are maintained in sys/unix/mod.rs - decode_error_kind(i32) + // The error codes are maintained in sys/unix/voice_conversion_to_weights - decode_error_kind(i32) const E_CROSSES_DEVICES : i32 = 18; // pub const EXDEV: ::c_int = 18; if is_filesystem_full_error(&err) { diff --git a/crates/lib/mysql_queries/src/queries/voice_conversion/models/list_whole_voice_conversion_models_using_cursor.rs b/crates/lib/mysql_queries/src/queries/voice_conversion/models/list_whole_voice_conversion_models_using_cursor.rs new file mode 100644 index 0000000000..4fdea8b17e --- /dev/null +++ b/crates/lib/mysql_queries/src/queries/voice_conversion/models/list_whole_voice_conversion_models_using_cursor.rs @@ -0,0 +1,249 @@ +use anyhow::anyhow; +use chrono::{DateTime, Utc}; +use log::warn; +use sqlx::{MySql, MySqlPool}; +use sqlx::pool::PoolConnection; + +use enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType; +use enums::common::visibility::Visibility; +use errors::AnyhowResult; +use tokens::tokens::model_weights::ModelWeightToken; +use tokens::tokens::users::UserToken; +use tokens::tokens::vocoder_models::VocoderModelToken; +use tokens::tokens::voice_conversion_models::VoiceConversionModelToken; + +use crate::helpers::boolean_converters::{i8_to_bool, nullable_i8_to_optional_bool}; + +#[derive(Debug)] +pub struct WholeVoiceConversionModelRecord { + pub id: i64, + pub token: VoiceConversionModelToken, + + pub model_type: VoiceConversionModelType, + pub maybe_model_vocoder_token: Option, + + pub title: String, + pub description_markdown: String, + pub description_rendered_html: String, + + pub ietf_language_tag: String, + pub ietf_primary_language_subtag: String, + + pub has_index_file: bool, + + pub is_front_page_featured: bool, + + pub original_download_url: Option, + pub original_filename: Option, + pub file_size_bytes: i32, + + pub creator_user_token: UserToken, + + pub ip_address_creation: String, + pub ip_address_last_update: String, + + pub maybe_last_update_user_token: Option, + + pub creator_set_visibility: Visibility, + + pub private_bucket_hash: String, + pub private_bucket_object_name: String, + + pub is_public_listing_approved: Option, + pub is_locked_from_user_modification: bool, + + pub maybe_mod_comments: Option, + + pub maybe_migration_new_model_weights_token: Option, + + pub version: i32, + + pub created_at: DateTime, + pub updated_at: DateTime, + + pub user_deleted_at: Option>, + pub mod_deleted_at: Option>, +} + +pub async fn list_whole_voice_conversion_models_using_cursor( + mysql_pool: &MySqlPool, + page_size: u64, + cursor: u64, +) -> AnyhowResult> { + let mut connection = mysql_pool.acquire().await?; + + let maybe_models + = list_whole_voice_conversion_models(&mut connection, page_size, cursor) + .await; + + let models : Vec = match maybe_models { + Ok(models) => models, + Err(err) => { + match err { + RowNotFound => { + return Ok(Vec::new()); + }, + _ => { + warn!("vc model list query error: {:?}", err); + return Err(anyhow!("vc model list query error")); + } + } + } + }; + + Ok(models.into_iter() + .map(|model| { + WholeVoiceConversionModelRecord { + id: model.id, + token: model.token, + model_type: model.model_type, + maybe_model_vocoder_token: model.maybe_vocoder_token, + title: model.title, + description_markdown: model.description_markdown, + description_rendered_html: model.description_rendered_html, + ietf_language_tag: model.ietf_language_tag, + ietf_primary_language_subtag: model.ietf_primary_language_subtag, + has_index_file: i8_to_bool(model.has_index_file), + is_front_page_featured: i8_to_bool(model.is_front_page_featured), + original_download_url: model.original_download_url, + original_filename: model.original_filename, + file_size_bytes: model.file_size_bytes, + creator_user_token: model.creator_user_token, + ip_address_creation: model.ip_address_creation, + ip_address_last_update: model.ip_address_last_update, + maybe_last_update_user_token: model.maybe_last_update_user_token, + creator_set_visibility: model.creator_set_visibility, + private_bucket_hash: model.private_bucket_hash, + private_bucket_object_name: model.private_bucket_object_name, + is_public_listing_approved: nullable_i8_to_optional_bool(model.is_public_listing_approved), + is_locked_from_user_modification: i8_to_bool(model.is_locked_from_user_modification), + maybe_mod_comments: model.maybe_mod_comments, + maybe_migration_new_model_weights_token: model.maybe_migration_new_model_weights_token, + version: model.version, + created_at: model.created_at, + updated_at: model.updated_at, + user_deleted_at: model.user_deleted_at, + mod_deleted_at: model.mod_deleted_at, + } + }) + .collect::>()) +} + +async fn list_whole_voice_conversion_models( + mysql_connection: &mut PoolConnection, + page_size: u64, + cursor: u64, +) -> AnyhowResult> { + Ok(sqlx::query_as!( + RawRecord, + r#" +SELECT + id, + token as `token: tokens::tokens::voice_conversion_models::VoiceConversionModelToken`, + + model_type as `model_type: enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType`, + maybe_vocoder_token as `maybe_vocoder_token: tokens::tokens::vocoder_models::VocoderModelToken`, + + title, + description_markdown, + description_rendered_html, + + ietf_language_tag, + ietf_primary_language_subtag, + + has_index_file, + + is_front_page_featured, + + original_download_url, + original_filename, + file_size_bytes, + + creator_user_token as `creator_user_token: tokens::tokens::users::UserToken`, + + ip_address_creation, + ip_address_last_update, + + maybe_last_update_user_token as `maybe_last_update_user_token: tokens::tokens::users::UserToken`, + + creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`, + + private_bucket_hash, + private_bucket_object_name, + + is_public_listing_approved, + is_locked_from_user_modification, + maybe_mod_comments, + + maybe_migration_new_model_weights_token as `maybe_migration_new_model_weights_token: tokens::tokens::model_weights::ModelWeightToken`, + + version, + + created_at, + updated_at, + + user_deleted_at, + mod_deleted_at + +FROM voice_conversion_models +WHERE + id > ? +ORDER BY id ASC +LIMIT ? + "#, + cursor, + page_size + ) + .fetch_all(&mut **mysql_connection) + .await?) +} + +struct RawRecord { + pub id: i64, + pub token: VoiceConversionModelToken, + + pub model_type: VoiceConversionModelType, + pub maybe_vocoder_token: Option, + + pub title: String, + pub description_markdown: String, + pub description_rendered_html: String, + + pub ietf_language_tag: String, + pub ietf_primary_language_subtag: String, + + pub has_index_file: i8, // bool + + pub is_front_page_featured: i8, // bool + + pub original_download_url: Option, + pub original_filename: Option, + pub file_size_bytes: i32, + + pub creator_user_token: UserToken, + + pub ip_address_creation: String, + pub ip_address_last_update: String, + + pub maybe_last_update_user_token: Option, + + pub creator_set_visibility: Visibility, + + pub private_bucket_hash: String, + pub private_bucket_object_name: String, + + pub is_public_listing_approved: Option, // bool + pub is_locked_from_user_modification: i8, // bool + + pub maybe_mod_comments: Option, + + pub maybe_migration_new_model_weights_token: Option, + + pub version: i32, + + pub created_at: DateTime, + pub updated_at: DateTime, + + pub user_deleted_at: Option>, + pub mod_deleted_at: Option>, +} diff --git a/crates/lib/mysql_queries/src/queries/voice_conversion/models/mod.rs b/crates/lib/mysql_queries/src/queries/voice_conversion/models/mod.rs index 3a04e54d4f..4df861aeb7 100644 --- a/crates/lib/mysql_queries/src/queries/voice_conversion/models/mod.rs +++ b/crates/lib/mysql_queries/src/queries/voice_conversion/models/mod.rs @@ -1,2 +1,3 @@ pub mod insert_voice_conversion_model_from_download_job; pub mod list_voice_conversion_models; +pub mod list_whole_voice_conversion_models_using_cursor; From bacb3ce5b1c456b51cd0748d1680aed1574e20b9 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Sun, 17 Dec 2023 01:53:42 -0500 Subject: [PATCH 063/124] migration code wip --- .../voice_conversion_to_weights/migrate.rs | 4 +- .../queries/model_weights/migration/mod.rs | 1 + ...odel_weight_from_voice_conversion_model.rs | 192 ++++++++++++++++++ .../src/queries/model_weights/mod.rs | 1 + ...le_voice_conversion_models_using_cursor.rs | 1 + 5 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 crates/lib/mysql_queries/src/queries/model_weights/migration/mod.rs create mode 100644 crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs diff --git a/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/migrate.rs b/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/migrate.rs index 9513ad2c0b..408bc379de 100644 --- a/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/migrate.rs +++ b/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/migrate.rs @@ -1,6 +1,7 @@ use std::thread; use std::time::Duration; use errors::AnyhowResult; +use mysql_queries::queries::model_weights::migration::upsert_model_weight_from_voice_conversion_model::upsert_model_weight_from_voice_conversion_model; use mysql_queries::queries::voice_conversion::models::list_whole_voice_conversion_models_using_cursor::list_whole_voice_conversion_models_using_cursor; use crate::deps::Deps; @@ -20,7 +21,8 @@ pub async fn migrate_voice_conversion_to_weights(deps: &Deps) -> AnyhowResult<() } for result in results.iter() { - println!("result: {:?}", result); + println!("result: {:?}\n\n", result); + upsert_model_weight_from_voice_conversion_model(result, &deps.mysql_development).await?; } if let Some(last_id) = results.last().map(|result| result.id) { diff --git a/crates/lib/mysql_queries/src/queries/model_weights/migration/mod.rs b/crates/lib/mysql_queries/src/queries/model_weights/migration/mod.rs new file mode 100644 index 0000000000..2789fecc14 --- /dev/null +++ b/crates/lib/mysql_queries/src/queries/model_weights/migration/mod.rs @@ -0,0 +1 @@ +pub mod upsert_model_weight_from_voice_conversion_model; \ No newline at end of file diff --git a/crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs b/crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs new file mode 100644 index 0000000000..0f571aa6ad --- /dev/null +++ b/crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs @@ -0,0 +1,192 @@ +use anyhow::anyhow; +use sqlx::{Acquire, MySql, MySqlPool, Transaction}; +use enums::by_table::model_weights::weights_category::WeightsCategory; +use enums::by_table::model_weights::weights_types::WeightsType; +use enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType; + +use errors::AnyhowResult; +use tokens::tokens::model_weights::ModelWeightToken; + +use crate::queries::voice_conversion::models::list_whole_voice_conversion_models_using_cursor::WholeVoiceConversionModelRecord; + +/// Migrate `voice_conversion_models` records to `model_weights` + `model_weights_extension_voice_conversion_details` records. +/// This is designed to be idempotent and re-runnable. Any time we re-run the query, we should get the same result. +/// This will enable us to perfect the query and get the write flows online and switched over. +/// +pub async fn upsert_model_weight_from_voice_conversion_model( + record: &WholeVoiceConversionModelRecord, + mysql_pool: &MySqlPool, +) -> AnyhowResult<()> { + //let mut connection = mysql_pool.acquire().await?; + let mut transaction = mysql_pool.begin().await?; + + let model_weight_token = create_or_generate_token(record); + + upsert_model_weights_record(record, &model_weight_token, &mut transaction).await?; + + // TODO: Don't update source record with new token *unless* we're backfilling the same database. + + transaction.commit().await?; + + Ok(()) +} + +pub fn create_or_generate_token(record: &WholeVoiceConversionModelRecord) -> ModelWeightToken { + match record.maybe_migration_new_model_weights_token { + Some(ref token) => token.clone(), + None => ModelWeightToken::generate(), + } +} + +pub async fn upsert_model_weights_record( + record: &WholeVoiceConversionModelRecord, + model_weight_token: &ModelWeightToken, + mut transaction: &mut Transaction<'_, MySql> +) -> AnyhowResult<()> { + + let weights_type = match record.model_type { + VoiceConversionModelType::SoftVc => return Err(anyhow!("we never built softvc models")), + VoiceConversionModelType::RvcV2 => WeightsType::RvcV2, + VoiceConversionModelType::SoVitsSvc => WeightsType::SoVitsSvc, + }; + + const WEIGHTS_CATEGORY : WeightsCategory = WeightsCategory::VoiceConversion; + + // NB: Not setting a few fields (for now) + // maybe_last_update_user_token - seems like bad design + // TODO(bt): OBVIOUSLY COPY THE BUCKET FILES ! + // TODO(bt): file checksum + // TODO(bt): rename maybe_private_bucket_extension to maybe_private_bucket_suffix. + // TODO(bt): do we need model_weights.ip_address_last_update without audit logs? + // TODO(bt): rename creator_ip_address to ip_address_creation (and add ip_address_last_update) + let query = sqlx::query!( + r#" +INSERT INTO model_weights +SET + token = ?, + weights_type = ?, + weights_category = ?, + title = ?, + maybe_thumbnail_token = NULL, + maybe_avatar_media_file_token = NULL, + maybe_cover_media_file_token = NULL, + description_markdown = ?, + description_rendered_html = ?, + creator_user_token = ?, + creator_ip_address = ?, + creator_set_visibility = ?, + maybe_last_update_user_token = NULL, + original_download_url = ?, + original_filename = ?, + file_size_bytes = ?, + file_checksum_sha2 = NULL, + private_bucket_hash = "TODO", + maybe_private_bucket_prefix = "TODO", + maybe_private_bucket_extension = "TODO", + cached_user_ratings_total_count = 0, + cached_user_ratings_positive_count = 0, + cached_user_ratings_negative_count = 0, + maybe_cached_user_ratings_ratio = 0.0, + cached_user_ratings_last_updated_at = NOW(), + maybe_migration_old_model_token = ?, + version = ?, + created_at = ?, + updated_at = ?, + user_deleted_at = ?, + mod_deleted_at = ? + +ON DUPLICATE KEY UPDATE + weights_type = ?, + weights_category = ?, + title = ?, + maybe_thumbnail_token = NULL, + maybe_avatar_media_file_token = NULL, + maybe_cover_media_file_token = NULL, + description_markdown = ?, + description_rendered_html = ?, + creator_user_token = ?, + creator_ip_address = ?, + creator_set_visibility = ?, + maybe_last_update_user_token = NULL, + original_download_url = ?, + original_filename = ?, + file_size_bytes = ?, + file_checksum_sha2 = NULL, + private_bucket_hash = "TODO", + maybe_private_bucket_prefix = "TODO", + maybe_private_bucket_extension = "TODO", + cached_user_ratings_total_count = 0, + cached_user_ratings_positive_count = 0, + cached_user_ratings_negative_count = 0, + maybe_cached_user_ratings_ratio = 0.0, + cached_user_ratings_last_updated_at = NOW(), + maybe_migration_old_model_token = ?, + version = ?, + created_at = ?, + updated_at = ?, + user_deleted_at = ?, + mod_deleted_at = ? + + "#, + // Insert + model_weight_token, + weights_type, + WEIGHTS_CATEGORY, + record.title, + record.description_markdown, + record.description_rendered_html, + record.creator_user_token, + record.ip_address_creation, + record.creator_set_visibility, + record.original_download_url, + record.original_filename, + record.file_size_bytes, + record.token.as_str(), + record.version, + record.created_at, + record.updated_at, + record.user_deleted_at, + record.mod_deleted_at, + + // Update + weights_type, + WEIGHTS_CATEGORY, + record.title, + record.description_markdown, + record.description_rendered_html, + record.creator_user_token, + record.ip_address_creation, + record.creator_set_visibility, + record.original_download_url, + record.original_filename, + record.file_size_bytes, + record.token.as_str(), + record.version, + record.created_at, + record.updated_at, + record.user_deleted_at, + record.mod_deleted_at, + ); + + let _r = query.execute(&mut **transaction).await?; + + Ok(()) +} + +pub async fn upsert_model_weights_extension_record( + record: &WholeVoiceConversionModelRecord, + model_weight_token: &ModelWeightToken, + transaction: &mut Transaction<'_, MySql> +) -> AnyhowResult<()> { + + Ok(()) +} + +pub async fn update_original_record( + record: &WholeVoiceConversionModelRecord, + model_weight_token: &ModelWeightToken, + transaction: &mut Transaction<'_, MySql> +) -> AnyhowResult<()> { + + Ok(()) +} diff --git a/crates/lib/mysql_queries/src/queries/model_weights/mod.rs b/crates/lib/mysql_queries/src/queries/model_weights/mod.rs index 06aeec0264..f18223ec5c 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/mod.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/mod.rs @@ -4,5 +4,6 @@ pub mod get_weight; pub mod list_weights_by_tokens; pub mod list_weights_by_user; pub mod list_weights_query_builder; +pub mod migration; pub mod tests; pub mod update_weight; diff --git a/crates/lib/mysql_queries/src/queries/voice_conversion/models/list_whole_voice_conversion_models_using_cursor.rs b/crates/lib/mysql_queries/src/queries/voice_conversion/models/list_whole_voice_conversion_models_using_cursor.rs index 4fdea8b17e..33335c5628 100644 --- a/crates/lib/mysql_queries/src/queries/voice_conversion/models/list_whole_voice_conversion_models_using_cursor.rs +++ b/crates/lib/mysql_queries/src/queries/voice_conversion/models/list_whole_voice_conversion_models_using_cursor.rs @@ -14,6 +14,7 @@ use tokens::tokens::voice_conversion_models::VoiceConversionModelToken; use crate::helpers::boolean_converters::{i8_to_bool, nullable_i8_to_optional_bool}; +/// This is meant to be the entire table #[derive(Debug)] pub struct WholeVoiceConversionModelRecord { pub id: i64, From b17b1f565cbab9b774a81c91c29e3bb288bc5778 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Sun, 17 Dec 2023 02:24:00 -0500 Subject: [PATCH 064/124] working --- ...t_model_weight_from_voice_conversion_model.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs b/crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs index 0f571aa6ad..6e7dd39bae 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs @@ -56,9 +56,10 @@ pub async fn upsert_model_weights_record( // maybe_last_update_user_token - seems like bad design // TODO(bt): OBVIOUSLY COPY THE BUCKET FILES ! // TODO(bt): file checksum - // TODO(bt): rename maybe_private_bucket_extension to maybe_private_bucket_suffix. + // TODO(bt): rename maybe_private_bucket_extension to maybe_private_bucket_suffix (!!!) // TODO(bt): do we need model_weights.ip_address_last_update without audit logs? // TODO(bt): rename creator_ip_address to ip_address_creation (and add ip_address_last_update) + // TODO(bt): Check model_weights column integer types - signed vs unsigned let query = sqlx::query!( r#" INSERT INTO model_weights @@ -74,12 +75,14 @@ SET description_rendered_html = ?, creator_user_token = ?, creator_ip_address = ?, + creator_set_visibility = ?, maybe_last_update_user_token = NULL, original_download_url = ?, original_filename = ?, file_size_bytes = ?, - file_checksum_sha2 = NULL, + file_checksum_sha2 = "TODO", + private_bucket_hash = "TODO", maybe_private_bucket_prefix = "TODO", maybe_private_bucket_extension = "TODO", @@ -88,6 +91,7 @@ SET cached_user_ratings_negative_count = 0, maybe_cached_user_ratings_ratio = 0.0, cached_user_ratings_last_updated_at = NOW(), + maybe_migration_old_model_token = ?, version = ?, created_at = ?, @@ -111,7 +115,7 @@ ON DUPLICATE KEY UPDATE original_download_url = ?, original_filename = ?, file_size_bytes = ?, - file_checksum_sha2 = NULL, + file_checksum_sha2 = "TODO", private_bucket_hash = "TODO", maybe_private_bucket_prefix = "TODO", maybe_private_bucket_extension = "TODO", @@ -126,7 +130,6 @@ ON DUPLICATE KEY UPDATE updated_at = ?, user_deleted_at = ?, mod_deleted_at = ? - "#, // Insert model_weight_token, @@ -137,10 +140,11 @@ ON DUPLICATE KEY UPDATE record.description_rendered_html, record.creator_user_token, record.ip_address_creation, - record.creator_set_visibility, + record.creator_set_visibility.to_str(), record.original_download_url, record.original_filename, record.file_size_bytes, + record.token.as_str(), record.version, record.created_at, @@ -156,7 +160,7 @@ ON DUPLICATE KEY UPDATE record.description_rendered_html, record.creator_user_token, record.ip_address_creation, - record.creator_set_visibility, + record.creator_set_visibility.to_str(), record.original_download_url, record.original_filename, record.file_size_bytes, From d518d544719b43bce28ea26dfb83b19942e407e3 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Mon, 18 Dec 2023 00:49:19 -0500 Subject: [PATCH 065/124] download job query --- Cargo.lock | 1 + ...ight_from_voice_conversion_download_job.rs | 142 ++++++++++++++++++ .../src/queries/model_weights/create/mod.rs | 1 + .../src/queries/model_weights/mod.rs | 1 + crates/service/job/download_job/Cargo.toml | 1 + .../rvc_v2/process_rvc_v2_model.rs | 34 ++++- .../so_vits_svc/process_so_vits_svc_model.rs | 34 ++++- 7 files changed, 210 insertions(+), 4 deletions(-) create mode 100644 crates/lib/mysql_queries/src/queries/model_weights/create/create_model_weight_from_voice_conversion_download_job.rs create mode 100644 crates/lib/mysql_queries/src/queries/model_weights/create/mod.rs diff --git a/Cargo.lock b/Cargo.lock index a6a2c3ec3d..10c9daad42 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1906,6 +1906,7 @@ dependencies = [ "subprocess", "subprocess_common", "tempdir", + "tokens", "tokio", "zip", ] diff --git a/crates/lib/mysql_queries/src/queries/model_weights/create/create_model_weight_from_voice_conversion_download_job.rs b/crates/lib/mysql_queries/src/queries/model_weights/create/create_model_weight_from_voice_conversion_download_job.rs new file mode 100644 index 0000000000..e066c68045 --- /dev/null +++ b/crates/lib/mysql_queries/src/queries/model_weights/create/create_model_weight_from_voice_conversion_download_job.rs @@ -0,0 +1,142 @@ +use std::path::Path; + +use anyhow::anyhow; +use sqlx::MySqlPool; +use enums::by_table::model_weights::weights_category::WeightsCategory; +use enums::by_table::model_weights::weights_types::WeightsType; + +use enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType; +use enums::common::visibility::Visibility; +use errors::AnyhowResult; +use tokens::tokens::model_weights::ModelWeightToken; +use tokens::tokens::users::UserToken; +use tokens::tokens::voice_conversion_models::VoiceConversionModelToken; + +pub struct CreateModelWeightArgs<'a> { + pub maybe_use_model_weights_token: Option, + pub maybe_old_voice_conversion_model_token: Option, + + pub weights_type: WeightsType, + pub weights_category: WeightsCategory, + + pub title: &'a str, + + pub original_download_url: &'a str, + pub original_filename: &'a str, + pub file_size_bytes: u64, + + pub creator_user_token: &'a UserToken, + pub creator_ip_address: &'a str, + pub creator_set_visibility: Visibility, + + /// (For rvc_v2 models) - whether the model has an associated `.index` file. + pub has_index_file: bool, + + pub public_bucket_hash: String, + pub maybe_public_bucket_prefix: Option, + pub maybe_public_bucket_extension: Option, + + pub mysql_pool: &'a MySqlPool, +} + +pub async fn create_model_weight_from_voice_conversion_download_job( + args: CreateModelWeightArgs<'_>, +) -> AnyhowResult<(u64, ModelWeightToken)> { + + let weights_token = args.maybe_use_model_weights_token + .map(|token| token.clone()) + .unwrap_or_else(|| ModelWeightToken::generate()); + + let mut transaction = args.mysql_pool.begin().await?; + + // NB: Not setting the following: + // - created_at + // - updated_at + // - user_deleted_at + // - mod_deleted_at + // - version = 0 + + let query_result = sqlx::query!( + r#" +INSERT INTO model_weights +SET + token = ?, + weights_type = ?, + weights_category = ?, + title = ?, + + maybe_thumbnail_token = NULL, + maybe_avatar_media_file_token = NULL, + maybe_cover_media_file_token = NULL, + description_markdown = NULL, + description_rendered_html = NULL, + + maybe_last_update_user_token = NULL, + original_download_url = ?, + original_filename = ?, + file_size_bytes = ?, + file_checksum_sha2 = "TODO", + + creator_user_token = ?, + creator_ip_address = ?, + creator_set_visibility = ?, + + private_bucket_hash = ?, + maybe_private_bucket_prefix = ?, + maybe_private_bucket_extension = ?, + + cached_user_ratings_total_count = 0, + cached_user_ratings_positive_count = 0, + cached_user_ratings_negative_count = 0, + maybe_cached_user_ratings_ratio = 0.0, + cached_user_ratings_last_updated_at = NOW(), + + maybe_migration_old_model_token = ? + "#, + &weights_token, + args.weights_type, + args.weights_category, + args.title, + + args.original_download_url, + args.original_filename, + args.file_size_bytes, + + args.creator_user_token, + args.creator_ip_address, + args.creator_set_visibility.to_str(), + + args.public_bucket_hash, + args.maybe_public_bucket_prefix, + args.maybe_public_bucket_extension, + + args.maybe_old_voice_conversion_model_token, + ) + .execute(&mut *transaction) + .await; + + let model_weights_record_id = match query_result { + Ok(res) => res.last_insert_id(), + Err(err) => return Err(anyhow!("Mysql error: {:?}", err)), + }; + + let query_result = sqlx::query!( + r#" +INSERT INTO model_weights_extension_voice_conversion_details +SET + model_weights_token = ?, + has_index_file = ? + "#, + &weights_token, + args.has_index_file + ) + .execute(&mut *transaction) + .await; + + match query_result { + Ok(_res) => {}, + Err(err) => return Err(anyhow!("Mysql error: {:?}", err)), + }; + + Ok((model_weights_record_id, weights_token)) +} diff --git a/crates/lib/mysql_queries/src/queries/model_weights/create/mod.rs b/crates/lib/mysql_queries/src/queries/model_weights/create/mod.rs new file mode 100644 index 0000000000..2b876c4c48 --- /dev/null +++ b/crates/lib/mysql_queries/src/queries/model_weights/create/mod.rs @@ -0,0 +1 @@ +pub mod create_model_weight_from_voice_conversion_download_job; \ No newline at end of file diff --git a/crates/lib/mysql_queries/src/queries/model_weights/mod.rs b/crates/lib/mysql_queries/src/queries/model_weights/mod.rs index f18223ec5c..e4ca37a05b 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/mod.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/mod.rs @@ -1,3 +1,4 @@ +pub mod create; pub mod create_weight; pub mod delete_weights; pub mod get_weight; diff --git a/crates/service/job/download_job/Cargo.toml b/crates/service/job/download_job/Cargo.toml index e97068915d..98ec26fcb2 100644 --- a/crates/service/job/download_job/Cargo.toml +++ b/crates/service/job/download_job/Cargo.toml @@ -32,6 +32,7 @@ mimetypes = { path = "../../../lib/files/mimetypes" } mysql_queries = { path = "../../../lib/mysql_queries" } reusable_types = { path = "../../../_types/reusable_types" } subprocess_common = { path = "../../../lib/subprocess_common" } +tokens = { path = "../../../_types/tokens" } # Workspace hack (faster compile times) my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" } diff --git a/crates/service/job/download_job/src/job_types/voice_conversion/rvc_v2/process_rvc_v2_model.rs b/crates/service/job/download_job/src/job_types/voice_conversion/rvc_v2/process_rvc_v2_model.rs index a7f7fea4d3..9d2eaa3542 100644 --- a/crates/service/job/download_job/src/job_types/voice_conversion/rvc_v2/process_rvc_v2_model.rs +++ b/crates/service/job/download_job/src/job_types/voice_conversion/rvc_v2/process_rvc_v2_model.rs @@ -5,6 +5,8 @@ use log::{error, info, warn}; use tempdir::TempDir; use crockford::crockford_entropy_lower; +use enums::by_table::model_weights::weights_category::WeightsCategory; +use enums::by_table::model_weights::weights_types::WeightsType; use enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType; use enums::common::visibility::Visibility; use errors::AnyhowResult; @@ -15,7 +17,9 @@ use filesys::safe_delete_temp_directory::safe_delete_temp_directory; use filesys::safe_delete_temp_file::safe_delete_temp_file; use jobs_common::redis_job_status_logger::RedisJobStatusLogger; use mysql_queries::queries::generic_download::job::list_available_generic_download_jobs::AvailableDownloadJob; +use mysql_queries::queries::model_weights::create::create_model_weight_from_voice_conversion_download_job::{create_model_weight_from_voice_conversion_download_job, CreateModelWeightArgs}; use mysql_queries::queries::voice_conversion::models::insert_voice_conversion_model_from_download_job::{insert_voice_conversion_model_from_download_job, InsertVoiceConversionModelArgs}; +use tokens::tokens::model_weights::ModelWeightToken; use crate::job_loop::job_results::JobResults; use crate::job_types::voice_conversion::rvc_v2::extract_rvc_files::{DownloadedRvcFile, extract_rvc_files}; @@ -140,6 +144,8 @@ pub async fn process_rvc_v2_model<'a, 'b>( } } + // TODO(bt, 2023-12-18): Upload model weights files !! + // ==================== DELETE DOWNLOADED FILE ==================== // // NB: We should be using a tempdir, but to make absolutely certain we don't overflow the disk... @@ -153,7 +159,10 @@ pub async fn process_rvc_v2_model<'a, 'b>( info!("Saving Voice Conversion model record..."); - let (_id, model_token) = insert_voice_conversion_model_from_download_job(InsertVoiceConversionModelArgs { + // TODO(bt,2023-12-18): Once migration is done, move this back into the query code. + let model_weights_token = ModelWeightToken::generate(); + + let (_id, voice_conversion_model_token) = insert_voice_conversion_model_from_download_job(InsertVoiceConversionModelArgs { model_type: VoiceConversionModelType::RvcV2, title: &job.title, original_download_url: &job.download_url, @@ -168,6 +177,27 @@ pub async fn process_rvc_v2_model<'a, 'b>( mysql_pool: &job_state.mysql_pool, }).await?; + info!("Saving model weights record..."); + + let (_id, _model_weights_token) = create_model_weight_from_voice_conversion_download_job(CreateModelWeightArgs { + maybe_use_model_weights_token: Some(model_weights_token.clone()), + maybe_old_voice_conversion_model_token: Some(voice_conversion_model_token.clone()), + weights_type: WeightsType::RvcV2, + weights_category: WeightsCategory::VoiceConversion, + title: &job.title, + original_download_url: &job.download_url, + original_filename: &download_filename, + file_size_bytes, + creator_user_token: &job.creator_user_token, + creator_ip_address: &job.creator_ip_address, + creator_set_visibility: Visibility::Public, // TODO: All models default to public at start + has_index_file: maybe_original_model_index_file_path.is_some(), + public_bucket_hash: "TODO".to_string(), // TODO: This needs to be finished. + maybe_public_bucket_prefix: None, + maybe_public_bucket_extension: None, + mysql_pool: &job_state.mysql_pool, + }).await?; + job_state.badge_granter.maybe_grant_voice_conversion_model_uploads_badge(&job.creator_user_token) .await .map_err(|e| { @@ -176,7 +206,7 @@ pub async fn process_rvc_v2_model<'a, 'b>( })?; Ok(JobResults { - entity_token: Some(model_token.to_string()), + entity_token: Some(voice_conversion_model_token.to_string()), // TODO: Swap model token. entity_type: Some(VoiceConversionModelType::RvcV2.to_string()), // NB: This may be different from `GenericDownloadType` in the future! }) } diff --git a/crates/service/job/download_job/src/job_types/voice_conversion/so_vits_svc/process_so_vits_svc_model.rs b/crates/service/job/download_job/src/job_types/voice_conversion/so_vits_svc/process_so_vits_svc_model.rs index d7500c91f3..6502bdbeb6 100644 --- a/crates/service/job/download_job/src/job_types/voice_conversion/so_vits_svc/process_so_vits_svc_model.rs +++ b/crates/service/job/download_job/src/job_types/voice_conversion/so_vits_svc/process_so_vits_svc_model.rs @@ -3,6 +3,8 @@ use std::path::PathBuf; use anyhow::anyhow; use log::{error, info, warn}; use tempdir::TempDir; +use enums::by_table::model_weights::weights_category::WeightsCategory; +use enums::by_table::model_weights::weights_types::WeightsType; use enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType; use enums::common::visibility::Visibility; @@ -14,7 +16,9 @@ use filesys::safe_delete_temp_file::safe_delete_temp_file; use hashing::sha256::sha256_hash_file::sha256_hash_file; use jobs_common::redis_job_status_logger::RedisJobStatusLogger; use mysql_queries::queries::generic_download::job::list_available_generic_download_jobs::AvailableDownloadJob; +use mysql_queries::queries::model_weights::create::create_model_weight_from_voice_conversion_download_job::{create_model_weight_from_voice_conversion_download_job, CreateModelWeightArgs}; use mysql_queries::queries::voice_conversion::models::insert_voice_conversion_model_from_download_job::{insert_voice_conversion_model_from_download_job, InsertVoiceConversionModelArgs}; +use tokens::tokens::model_weights::ModelWeightToken; use crate::job_loop::job_results::JobResults; use crate::job_types::voice_conversion::so_vits_svc::so_vits_svc_model_check_command::{CheckArgs, Device}; @@ -86,6 +90,8 @@ pub async fn process_so_vits_svc_model<'a, 'b>( return Err(err); } + // TODO(bt, 2023-12-18): Upload model weights files !! + // ==================== DELETE DOWNLOADED FILE ==================== // // NB: We should be using a tempdir, but to make absolutely certain we don't overflow the disk... @@ -98,7 +104,10 @@ pub async fn process_so_vits_svc_model<'a, 'b>( info!("Saving Voice Conversion model record..."); - let (_id, model_token) = insert_voice_conversion_model_from_download_job(InsertVoiceConversionModelArgs { + // TODO(bt,2023-12-18): Once migration is done, move this back into the query code. + let model_weights_token = ModelWeightToken::generate(); + + let (_id, voice_conversion_model_token) = insert_voice_conversion_model_from_download_job(InsertVoiceConversionModelArgs { model_type: VoiceConversionModelType::SoVitsSvc, title: &job.title, original_download_url: &job.download_url, @@ -113,6 +122,27 @@ pub async fn process_so_vits_svc_model<'a, 'b>( mysql_pool: &job_state.mysql_pool, }).await?; + info!("Saving model weights record..."); + + let (_id, _model_weights_token) = create_model_weight_from_voice_conversion_download_job(CreateModelWeightArgs { + maybe_use_model_weights_token: Some(model_weights_token.clone()), + maybe_old_voice_conversion_model_token: Some(voice_conversion_model_token.clone()), + weights_type: WeightsType::SoVitsSvc, + weights_category: WeightsCategory::VoiceConversion, + title: &job.title, + original_download_url: &job.download_url, + original_filename: &download_filename, + file_size_bytes, + creator_user_token: &job.creator_user_token, + creator_ip_address: &job.creator_ip_address, + creator_set_visibility: Visibility::Public, // TODO: All models default to public at start + has_index_file: false, // SVC do not have index files. + public_bucket_hash: "TODO".to_string(), // TODO: This needs to be finished. + maybe_public_bucket_prefix: None, + maybe_public_bucket_extension: None, + mysql_pool: &job_state.mysql_pool, + }).await?; + job_state.badge_granter.maybe_grant_voice_conversion_model_uploads_badge(&job.creator_user_token) .await .map_err(|e| { @@ -121,7 +151,7 @@ pub async fn process_so_vits_svc_model<'a, 'b>( })?; Ok(JobResults { - entity_token: Some(model_token.to_string()), + entity_token: Some(voice_conversion_model_token.to_string()), // TODO: Swap model token. entity_type: Some(VoiceConversionModelType::SoVitsSvc.to_string()), // NB: This may be different from `GenericDownloadType` in the future! }) } From 545417111285574872db047682bd6c119b789b2d Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Mon, 18 Dec 2023 00:58:29 -0500 Subject: [PATCH 066/124] move module --- ...psert_model_weight_from_voice_conversion_model.rs | 4 ++-- ...ist_whole_voice_conversion_models_using_cursor.rs | 0 .../src/queries/voice_conversion/migration/mod.rs | 1 + .../src/queries/voice_conversion/mod.rs | 1 + .../src/queries/voice_conversion/models/mod.rs | 1 - .../voice_conversion/rvc_v2/process_rvc_v2_model.rs | 12 ------------ 6 files changed, 4 insertions(+), 15 deletions(-) rename crates/lib/mysql_queries/src/queries/voice_conversion/{models => migration}/list_whole_voice_conversion_models_using_cursor.rs (100%) create mode 100644 crates/lib/mysql_queries/src/queries/voice_conversion/migration/mod.rs diff --git a/crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs b/crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs index 6e7dd39bae..c59b695c58 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs @@ -1,13 +1,13 @@ use anyhow::anyhow; use sqlx::{Acquire, MySql, MySqlPool, Transaction}; + use enums::by_table::model_weights::weights_category::WeightsCategory; use enums::by_table::model_weights::weights_types::WeightsType; use enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType; - use errors::AnyhowResult; use tokens::tokens::model_weights::ModelWeightToken; -use crate::queries::voice_conversion::models::list_whole_voice_conversion_models_using_cursor::WholeVoiceConversionModelRecord; +use crate::queries::voice_conversion::migration::list_whole_voice_conversion_models_using_cursor::WholeVoiceConversionModelRecord; /// Migrate `voice_conversion_models` records to `model_weights` + `model_weights_extension_voice_conversion_details` records. /// This is designed to be idempotent and re-runnable. Any time we re-run the query, we should get the same result. diff --git a/crates/lib/mysql_queries/src/queries/voice_conversion/models/list_whole_voice_conversion_models_using_cursor.rs b/crates/lib/mysql_queries/src/queries/voice_conversion/migration/list_whole_voice_conversion_models_using_cursor.rs similarity index 100% rename from crates/lib/mysql_queries/src/queries/voice_conversion/models/list_whole_voice_conversion_models_using_cursor.rs rename to crates/lib/mysql_queries/src/queries/voice_conversion/migration/list_whole_voice_conversion_models_using_cursor.rs diff --git a/crates/lib/mysql_queries/src/queries/voice_conversion/migration/mod.rs b/crates/lib/mysql_queries/src/queries/voice_conversion/migration/mod.rs new file mode 100644 index 0000000000..198fbb2acc --- /dev/null +++ b/crates/lib/mysql_queries/src/queries/voice_conversion/migration/mod.rs @@ -0,0 +1 @@ +pub mod list_whole_voice_conversion_models_using_cursor; diff --git a/crates/lib/mysql_queries/src/queries/voice_conversion/mod.rs b/crates/lib/mysql_queries/src/queries/voice_conversion/mod.rs index 962214e104..14446f8297 100644 --- a/crates/lib/mysql_queries/src/queries/voice_conversion/mod.rs +++ b/crates/lib/mysql_queries/src/queries/voice_conversion/mod.rs @@ -1,4 +1,5 @@ pub mod inference; +pub mod migration; pub mod model_info_lite; pub mod models; pub mod results; \ No newline at end of file diff --git a/crates/lib/mysql_queries/src/queries/voice_conversion/models/mod.rs b/crates/lib/mysql_queries/src/queries/voice_conversion/models/mod.rs index 4df861aeb7..3a04e54d4f 100644 --- a/crates/lib/mysql_queries/src/queries/voice_conversion/models/mod.rs +++ b/crates/lib/mysql_queries/src/queries/voice_conversion/models/mod.rs @@ -1,3 +1,2 @@ pub mod insert_voice_conversion_model_from_download_job; pub mod list_voice_conversion_models; -pub mod list_whole_voice_conversion_models_using_cursor; diff --git a/crates/service/job/download_job/src/job_types/voice_conversion/rvc_v2/process_rvc_v2_model.rs b/crates/service/job/download_job/src/job_types/voice_conversion/rvc_v2/process_rvc_v2_model.rs index 9d2eaa3542..f625647358 100644 --- a/crates/service/job/download_job/src/job_types/voice_conversion/rvc_v2/process_rvc_v2_model.rs +++ b/crates/service/job/download_job/src/job_types/voice_conversion/rvc_v2/process_rvc_v2_model.rs @@ -210,15 +210,3 @@ pub async fn process_rvc_v2_model<'a, 'b>( entity_type: Some(VoiceConversionModelType::RvcV2.to_string()), // NB: This may be different from `GenericDownloadType` in the future! }) } - -//#[cfg(test)] -//mod tests { -// use crockford_deprecated::crockford_entropy_lower; -// -// #[test] -// fn temp() { -// // need to make some hashes really quick -// let e = crockford_entropy_lower(64); -// assert_eq!(e, ""); -// } -//} From 04206055356d7c58d53c6b84924511a27be5652a Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Mon, 18 Dec 2023 01:10:02 -0500 Subject: [PATCH 067/124] inference query for weights (vc) --- ...l_weight_for_voice_conversion_inference.rs | 140 ++++++++++++++++++ .../queries/model_weights/inference/mod.rs | 1 + .../src/queries/model_weights/mod.rs | 1 + ...et_voice_conversion_model_for_inference.rs | 9 -- 4 files changed, 142 insertions(+), 9 deletions(-) create mode 100644 crates/lib/mysql_queries/src/queries/model_weights/inference/get_model_weight_for_voice_conversion_inference.rs create mode 100644 crates/lib/mysql_queries/src/queries/model_weights/inference/mod.rs diff --git a/crates/lib/mysql_queries/src/queries/model_weights/inference/get_model_weight_for_voice_conversion_inference.rs b/crates/lib/mysql_queries/src/queries/model_weights/inference/get_model_weight_for_voice_conversion_inference.rs new file mode 100644 index 0000000000..eee49ee78f --- /dev/null +++ b/crates/lib/mysql_queries/src/queries/model_weights/inference/get_model_weight_for_voice_conversion_inference.rs @@ -0,0 +1,140 @@ +use chrono::{DateTime, Utc}; +use log::warn; +use sqlx; +use sqlx::MySqlPool; + +use enums::by_table::model_weights::weights_types::WeightsType; +use tokens::tokens::model_weights::ModelWeightToken; + +use crate::helpers::boolean_converters::i8_to_bool; + +#[derive(Clone)] +pub struct ModelWeightForVoiceConversionInference { + pub token: ModelWeightToken, + pub weights_type: WeightsType, + + pub title: String, + + // (rvc_v2 models:) whether the model also has an associated index file. + pub has_index_file: bool, + + pub public_bucket_hash: String, + pub maybe_public_bucket_prefix: Option, + pub maybe_public_bucket_extension: Option, + + pub created_at: DateTime, + pub updated_at: DateTime, + + pub mod_deleted_at: Option>, + pub user_deleted_at: Option>, +} + +#[derive(Clone, Debug)] +pub enum ModelWeightError { + ModelDeleted, + DatabaseError { reason: String }, +} + +impl std::fmt::Display for ModelWeightError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ModelWeightError::ModelDeleted => write!(f, "ModelDeleted"), + ModelWeightError::DatabaseError { reason} => + write!(f, "Database error: {:?}", reason), + } + } +} + +impl std::error::Error for ModelWeightError {} + + +pub async fn get_model_weight_for_voice_conversion_inference( + pool: &MySqlPool, + model_weight_token: &ModelWeightToken +) -> Result, ModelWeightError> +{ + // NB: Lookup failure is Err(RowNotFound). + // NB: Since this is publicly exposed, we don't query sensitive data. + let maybe_model = sqlx::query_as!( + InternalRecord, + r#" +SELECT + w.token as `token: tokens::tokens::model_weights::ModelWeightToken`, + w.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`, + + w.title, + vc.has_index_file, + + w.private_bucket_hash, + w.maybe_private_bucket_prefix, + w.maybe_private_bucket_extension, + + w.created_at, + w.updated_at, + w.user_deleted_at, + w.mod_deleted_at + +FROM model_weights as w +JOIN model_weights_extension_voice_conversion_details as vc +ON vc.model_weights_token = w.token + +WHERE w.token = ? + "#, + model_weight_token + ) + .fetch_one(pool) + .await; // TODO: This will return error if it doesn't exist + + let model : InternalRecord = match maybe_model { + Ok(model) => model, + Err(err) => { + return match err { + sqlx::Error::RowNotFound => { + Ok(None) + }, + _ => { + warn!("voice conversion model query error: {:?}", err); + Err(ModelWeightError::DatabaseError { + reason: format!("Mysql error: {:?}", err) + }) + } + } + } + }; + + if model.mod_deleted_at.is_some() || model.user_deleted_at.is_some() { + return Err(ModelWeightError::ModelDeleted); + } + + Ok(Some(ModelWeightForVoiceConversionInference { + token: model.token, + weights_type: model.weights_type, + title: model.title, + has_index_file: i8_to_bool(model.has_index_file), + public_bucket_hash: model.private_bucket_hash, + maybe_public_bucket_prefix: model.maybe_private_bucket_prefix, + maybe_public_bucket_extension: model.maybe_private_bucket_extension, + created_at: model.created_at, + updated_at: model.updated_at, + mod_deleted_at: model.mod_deleted_at, + user_deleted_at: model.user_deleted_at, + })) +} + +struct InternalRecord { + token: ModelWeightToken, + weights_type: WeightsType, + + title: String, + + has_index_file: i8, + + private_bucket_hash: String, + maybe_private_bucket_prefix: Option, + maybe_private_bucket_extension: Option, + + created_at: DateTime, + updated_at: DateTime, + mod_deleted_at: Option>, + user_deleted_at: Option>, +} diff --git a/crates/lib/mysql_queries/src/queries/model_weights/inference/mod.rs b/crates/lib/mysql_queries/src/queries/model_weights/inference/mod.rs new file mode 100644 index 0000000000..d98b1ee486 --- /dev/null +++ b/crates/lib/mysql_queries/src/queries/model_weights/inference/mod.rs @@ -0,0 +1 @@ +pub mod get_model_weight_for_voice_conversion_inference; \ No newline at end of file diff --git a/crates/lib/mysql_queries/src/queries/model_weights/mod.rs b/crates/lib/mysql_queries/src/queries/model_weights/mod.rs index e4ca37a05b..fd09bc5721 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/mod.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/mod.rs @@ -2,6 +2,7 @@ pub mod create; pub mod create_weight; pub mod delete_weights; pub mod get_weight; +pub mod inference; pub mod list_weights_by_tokens; pub mod list_weights_by_user; pub mod list_weights_query_builder; diff --git a/crates/lib/mysql_queries/src/queries/voice_conversion/inference/get_voice_conversion_model_for_inference.rs b/crates/lib/mysql_queries/src/queries/voice_conversion/inference/get_voice_conversion_model_for_inference.rs index 5d5cb38190..7732546093 100644 --- a/crates/lib/mysql_queries/src/queries/voice_conversion/inference/get_voice_conversion_model_for_inference.rs +++ b/crates/lib/mysql_queries/src/queries/voice_conversion/inference/get_voice_conversion_model_for_inference.rs @@ -1,8 +1,3 @@ -// NB: Incrementally getting rid of build warnings... -//#![forbid(unused_imports)] -//#![forbid(unused_mut)] -//#![forbid(unused_variables)] - use chrono::{DateTime, Utc}; use log::warn; use sqlx; @@ -20,10 +15,6 @@ pub struct VoiceConversionModelForInference { pub title: String, - //pub creator_user_token: UserToken, - //pub creator_username: String, - //pub creator_display_name: String, - // (rvc_v2 models:) whether the model also has an associated index file. pub has_index_file: bool, From d03fb5ed0f7b19336556a699a7c13f217aa6b973 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Mon, 18 Dec 2023 14:19:41 -0500 Subject: [PATCH 068/124] migration support + tests --- .../inference_job/src/job/job_types/vc/mod.rs | 1 + .../job/job_types/vc/process_single_vc_job.rs | 72 ++-- .../job/job_types/vc/rvc_v2/process_job.rs | 17 +- .../job_types/vc/so_vits_svc/process_job.rs | 8 +- .../src/job/job_types/vc/vc_model.rs | 323 ++++++++++++++++++ 5 files changed, 382 insertions(+), 39 deletions(-) create mode 100644 crates/service/job/inference_job/src/job/job_types/vc/vc_model.rs diff --git a/crates/service/job/inference_job/src/job/job_types/vc/mod.rs b/crates/service/job/inference_job/src/job/job_types/vc/mod.rs index c0767e303d..dd6ecc5961 100644 --- a/crates/service/job/inference_job/src/job/job_types/vc/mod.rs +++ b/crates/service/job/inference_job/src/job/job_types/vc/mod.rs @@ -1,3 +1,4 @@ pub mod process_single_vc_job; pub mod rvc_v2; pub mod so_vits_svc; +pub mod vc_model; diff --git a/crates/service/job/inference_job/src/job/job_types/vc/process_single_vc_job.rs b/crates/service/job/inference_job/src/job/job_types/vc/process_single_vc_job.rs index d98751b1b6..8de19948a6 100644 --- a/crates/service/job/inference_job/src/job/job_types/vc/process_single_vc_job.rs +++ b/crates/service/job/inference_job/src/job/job_types/vc/process_single_vc_job.rs @@ -2,40 +2,36 @@ use std::time::Duration; use anyhow::anyhow; use log::{error, info}; +use sqlx::MySqlPool; +use enums::by_table::model_weights::weights_types::WeightsType; use enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType; +use errors::AnyhowResult; use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob; use mysql_queries::queries::media_uploads::get_media_upload_for_inference::get_media_upload_for_inference; -use mysql_queries::queries::voice_conversion::inference::get_voice_conversion_model_for_inference::get_voice_conversion_model_for_inference; +use mysql_queries::queries::model_weights::inference::get_model_weight_for_voice_conversion_inference::{get_model_weight_for_voice_conversion_inference, ModelWeightForVoiceConversionInference}; +use mysql_queries::queries::voice_conversion::inference::get_voice_conversion_model_for_inference::{get_voice_conversion_model_for_inference, VoiceConversionModelForInference}; use tokens::tokens::media_uploads::MediaUploadToken; +use tokens::tokens::model_weights::ModelWeightToken; use crate::job::job_loop::job_success_result::JobSuccessResult; use crate::job::job_loop::process_single_job_error::ProcessSingleJobError; use crate::job::job_types::vc::{rvc_v2, so_vits_svc}; use crate::job::job_types::vc::rvc_v2::process_job::RvcV2ProcessJobArgs; use crate::job::job_types::vc::so_vits_svc::process_job::SoVitsSvcProcessJobArgs; +use crate::job::job_types::vc::vc_model::{VcModel, VcModelType}; use crate::job_dependencies::JobDependencies; pub async fn process_single_vc_job(job_dependencies: &JobDependencies, job: &AvailableInferenceJob) -> Result { - let model_token = match job.maybe_model_token.as_deref() { Some(token) => token, - None => { - return Err(ProcessSingleJobError::InvalidJob( - anyhow!("No model token for job: {:?}", job.inference_job_token))); - } + None => return Err(ProcessSingleJobError::InvalidJob(anyhow!("No model token for job: {:?}", job.inference_job_token))), }; - // TODO: Interrogate cache (which also depends on other flags) - let maybe_vc_model = get_voice_conversion_model_for_inference( - &job_dependencies.db.mysql_pool, model_token) - .await - .map_err(|err| { - ProcessSingleJobError::Other(anyhow!("database error: {:?}", err)) - })?; + let maybe_model = query_model(model_token, &job_dependencies.db.mysql_pool).await?; - let vc_model = match maybe_vc_model { - None => return Err(ProcessSingleJobError::Other(anyhow!("vc model not found: {:?}", model_token))), + let model = match maybe_model { + None => return Err(ProcessSingleJobError::Other(anyhow!("model weights not found: {:?}", model_token))), Some(model) => model, }; @@ -72,42 +68,66 @@ pub async fn process_single_vc_job(job_dependencies: &JobDependencies, job: &Ava Ok(None) => { error!("no media upload record found for token: {:?}", media_upload_token); return Err(ProcessSingleJobError::Other(anyhow!("no media upload record found for token: {:?}", media_upload_token))); - }, + } Err(err) => { error!("error fetching media upload record from db: {:?}", err); return Err(ProcessSingleJobError::Other(err)); - }, + } }; info!("Source media upload file size (bytes): {}", &media_upload.original_file_size_bytes); info!("Source media upload duration (millis): {}", &media_upload.original_duration_millis); info!("Source media upload duration (seconds): {}", (media_upload.original_duration_millis as f32 / 1000.0)); - let job_success_result = match vc_model.model_type { - VoiceConversionModelType::RvcV2 => { + let job_success_result = match model.get_model_type() { + VcModelType::RvcV2 => { rvc_v2::process_job::process_job(RvcV2ProcessJobArgs { job_dependencies, job, - vc_model: &vc_model, + vc_model: &model, media_upload_token: &media_upload_token, media_upload: &media_upload, }).await? } - VoiceConversionModelType::SoVitsSvc => { + VcModelType::SoVitsSvc => { so_vits_svc::process_job::process_job(SoVitsSvcProcessJobArgs { job_dependencies, job, - vc_model: &vc_model, + vc_model: &model, media_upload_token: &media_upload_token, media_upload: &media_upload, }).await? } - VoiceConversionModelType::SoftVc => { - // TODO: Not yet implemented. - JobSuccessResult { maybe_result_entity: None, inference_duration: Duration::from_secs(0) } - } + VcModelType::SoftVc => return Err(ProcessSingleJobError::NotYetImplemented), + VcModelType::Invalid => return Err(ProcessSingleJobError::InvalidJob(anyhow!("invalid vc model type: {:?}", model.get_model_type()))), }; Ok(job_success_result) } + +async fn query_model(model_token: &str, mysql_pool: &MySqlPool) -> Result, ProcessSingleJobError> { + // TODO: Interrogate a db result cache + filesystem model file cache + + // NB: This is temporary migration code as we switch from the `voice_conversion_models` table to the `model_weights` table. + if model_token.starts_with(ModelWeightToken::token_prefix()) { + let model_weights_token = ModelWeightToken::new_from_str(model_token); + + let maybe_model = get_model_weight_for_voice_conversion_inference( + &mysql_pool, &model_weights_token) + .await + .map_err(|err| ProcessSingleJobError::Other(anyhow!("database error: {:?}", err)))?; + + Ok(maybe_model + .map(|model| VcModel::ModelWeight(model))) + + } else { + let maybe_vc_model = get_voice_conversion_model_for_inference( + &mysql_pool, model_token) + .await + .map_err(|err| ProcessSingleJobError::Other(anyhow!("database error: {:?}", err)))?; + + Ok(maybe_vc_model + .map(|model| VcModel::LegacyVoiceConversion(model))) + } +} diff --git a/crates/service/job/inference_job/src/job/job_types/vc/rvc_v2/process_job.rs b/crates/service/job/inference_job/src/job/job_types/vc/rvc_v2/process_job.rs index fb444a2a07..779366558e 100644 --- a/crates/service/job/inference_job/src/job/job_types/vc/rvc_v2/process_job.rs +++ b/crates/service/job/inference_job/src/job/job_types/vc/rvc_v2/process_job.rs @@ -20,13 +20,13 @@ use mysql_queries::payloads::generic_inference_args::generic_inference_args::Pol use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob; use mysql_queries::queries::media_files::insert_media_file_from_voice_conversion::{insert_media_file_from_voice_conversion, InsertMediaFileArgs, VoiceConversionModelType}; use mysql_queries::queries::media_uploads::get_media_upload_for_inference::MediaUploadRecordForInference; -use mysql_queries::queries::voice_conversion::inference::get_voice_conversion_model_for_inference::VoiceConversionModelForInference; use tokens::tokens::media_uploads::MediaUploadToken; use tokens::tokens::users::UserToken; use crate::job::job_loop::job_success_result::{JobSuccessResult, ResultEntity}; use crate::job::job_loop::process_single_job_error::ProcessSingleJobError; use crate::job::job_types::vc::rvc_v2::rvc_v2_inference_command::InferenceArgs; +use crate::job::job_types::vc::vc_model::VcModel; use crate::job_dependencies::JobDependencies; use crate::util::maybe_download_file_from_bucket::{maybe_download_file_from_bucket, MaybeDownloadArgs}; @@ -36,7 +36,7 @@ const BUCKET_FILE_EXTENSION : &str = ".wav"; pub struct RvcV2ProcessJobArgs<'a> { pub job_dependencies: &'a JobDependencies, pub job: &'a AvailableInferenceJob, - pub vc_model: &'a VoiceConversionModelForInference, + pub vc_model: &'a VcModel, pub media_upload_token: &'a MediaUploadToken, pub media_upload: &'a MediaUploadRecordForInference, } @@ -77,8 +77,7 @@ pub async fn process_job(args: RvcV2ProcessJobArgs<'_>) -> Result) -> Result) -> Result = None; - if vc_model.has_index_file { + if vc_model.has_index_file() { info!("Download RVC index (if not present)..."); maybe_rvc_v2_model_index_fs_path = { - let filename = format!("{}.index", vc_model.token.as_str()); - let fs_path = args.job_dependencies.fs.semi_persistent_cache.voice_conversion_model_path(&filename); + let fs_path = vc_model.get_index_file_persistent_filesystem_path(&args.job_dependencies.fs.semi_persistent_cache); create_dir_all_if_missing(args.job_dependencies.fs.semi_persistent_cache.voice_conversion_model_directory()) .map_err(|e| { @@ -142,7 +140,8 @@ pub async fn process_job(args: RvcV2ProcessJobArgs<'_>) -> Result { pub job_dependencies: &'a JobDependencies, pub job: &'a AvailableInferenceJob, - pub vc_model: &'a VoiceConversionModelForInference, + pub vc_model: &'a VcModel, pub media_upload_token: &'a MediaUploadToken, pub media_upload: &'a MediaUploadRecordForInference, } @@ -67,7 +67,7 @@ pub async fn process_job(args: SoVitsSvcProcessJobArgs<'_>) -> Result) -> Result VcModelType { + match self { + VcModel::LegacyVoiceConversion(ref model) => match model.model_type { + VoiceConversionModelType::RvcV2 => VcModelType::RvcV2, + VoiceConversionModelType::SoftVc => VcModelType::SoftVc, + VoiceConversionModelType::SoVitsSvc => VcModelType::SoVitsSvc, + } + VcModel::ModelWeight(ref model) => match model.weights_type { + // Valid types + WeightsType::SoVitsSvc => VcModelType::SoVitsSvc, + WeightsType::RvcV2 => VcModelType::RvcV2, + // Invalid types + WeightsType::StableDiffusion15 => VcModelType::Invalid, + WeightsType::HifiganTacotron2 => VcModelType::Invalid, + WeightsType::StableDiffusionXL => VcModelType::Invalid, + WeightsType::Tacotron2 => VcModelType::Invalid, + WeightsType::LoRA => VcModelType::Invalid, + WeightsType::VallE => VcModelType::Invalid, + } + } + } + + /// Whether the model has an associated speaker index file. Only applies to certain RVC models. + pub fn has_index_file(&self) -> bool { + match self { + VcModel::LegacyVoiceConversion(ref model) => { + match model.model_type { + VoiceConversionModelType::RvcV2 => model.has_index_file, + _ => false, + } + } + VcModel::ModelWeight(ref model) => { + match model.weights_type { + WeightsType::RvcV2 => model.has_index_file, + _ => false, + } + } + } + } + + /// Location where the SVC or RVC model weights are stored in the cloud bucket. + pub fn get_model_cloud_bucket_path(&self, bucket_path_unifier: &BucketPathUnifier) -> PathBuf { + match self { + VcModel::LegacyVoiceConversion(ref model) => { + match model.model_type { + VoiceConversionModelType::RvcV2 => { + bucket_path_unifier.rvc_v2_model_path(&model.private_bucket_hash) + } + VoiceConversionModelType::SoVitsSvc => { + bucket_path_unifier.so_vits_svc_model_path(&model.private_bucket_hash) + } + VoiceConversionModelType::SoftVc => { + // NB: Technically wrong, but there are none of these models and I want the + // method to be infallible since it is in all other cases. + PathBuf::from("SOFT_VC_UNUSED_AND_UNIMPLEMENTED") + } + } + } + VcModel::ModelWeight(ref model) => { + let path = WeightFileBucketPath::from_object_hash( + &model.public_bucket_hash, + model.maybe_public_bucket_prefix.as_deref(), + model.maybe_public_bucket_extension.as_deref()); + + PathBuf::from(path.get_full_object_path_str()) + } + } + } + + /// Location where the optional index file is stored in the cloud bucket. + /// Only RVC models have index files. + pub fn get_index_file_cloud_bucket_path(&self, bucket_path_unifier: &BucketPathUnifier) -> Option { + match self { + VcModel::LegacyVoiceConversion(ref model) => { + if !model.has_index_file { + return None; + } + match model.model_type { + VoiceConversionModelType::SoVitsSvc => None, + VoiceConversionModelType::SoftVc => None, + VoiceConversionModelType::RvcV2 => { + Some(bucket_path_unifier.rvc_v2_model_index_path(&model.private_bucket_hash)) + } + } + } + VcModel::ModelWeight(ref model) => { + if !model.has_index_file { + return None; + } + let path = WeightFileBucketPath::from_object_hash( + &model.public_bucket_hash, + model.maybe_public_bucket_prefix.as_deref(), + Some(".rvc_index")); + + Some(PathBuf::from(path.get_full_object_path_str())) + } + } + } + + /// We store models on the filesystem long term to speed up future instances of the job + /// that use the same model. This way we don't incur the same (time and monetary) costs + /// of downloading the model again and again. + pub fn get_model_persistent_filesystem_path(&self, cache_dir: &SemiPersistentCacheDir) -> PathBuf { + let token = match self { + VcModel::LegacyVoiceConversion(ref model) => model.token.as_str(), + VcModel::ModelWeight(ref model) => model.token.as_str(), + }; + let filename = format!("{token}.pt"); + cache_dir.voice_conversion_model_path(&filename) + } + + /// Same as `get_model_persistent_filesystem_path`, but for RVC index files. + /// This will return a valid path even if the model doesn't have an index file, so be sure + /// to check if the model has an index model first. + pub fn get_index_file_persistent_filesystem_path(&self, cache_dir: &SemiPersistentCacheDir) -> PathBuf { + let token = match self { + VcModel::LegacyVoiceConversion(ref model) => model.token.as_str(), + VcModel::ModelWeight(ref model) => model.token.as_str(), + }; + let filename = format!("{token}.index"); + cache_dir.voice_conversion_model_path(&filename) + } +} + +#[cfg(test)] +mod tests { + + mod legacy_voice_conversion_models { + use std::path::PathBuf; + + use cloud_storage::bucket_path_unifier::BucketPathUnifier; + use enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType; + use jobs_common::semi_persistent_cache_dir::SemiPersistentCacheDir; + use mysql_queries::queries::voice_conversion::inference::get_voice_conversion_model_for_inference::VoiceConversionModelForInference; + use tokens::tokens::voice_conversion_models::VoiceConversionModelToken; + + use crate::job::job_types::vc::vc_model::{VcModel, VcModelType}; + + fn default_model() -> VoiceConversionModelForInference { + // NB: We could implement/derive the default trait, but this works just as well for now. + VoiceConversionModelForInference { + token: VoiceConversionModelToken::new_from_str("vcm_entropy"), + model_type: VoiceConversionModelType::RvcV2, + private_bucket_hash: "hash".to_string(), + has_index_file: false, + title: "title".to_string(), + created_at: Default::default(), + updated_at: Default::default(), + user_deleted_at: None, + mod_deleted_at: None, + } + } + + #[test] + fn has_index_file() { + let mut model = default_model(); + model.has_index_file = false; + model.model_type = VoiceConversionModelType::RvcV2; + assert_eq!(VcModel::LegacyVoiceConversion(model).has_index_file(), false); + + let mut model = default_model(); + model.has_index_file = true; + model.model_type = VoiceConversionModelType::RvcV2; + assert_eq!(VcModel::LegacyVoiceConversion(model).has_index_file(), true); + } + + #[test] + fn get_model_persistent_file_path() { + let model = default_model(); + let path = VcModel::LegacyVoiceConversion(model).get_model_persistent_filesystem_path(&SemiPersistentCacheDir::default_paths()); + assert_eq!(path, PathBuf::from("/file_cache/voice_conversion/models/vcm_entropy.pt")); + } + + #[test] + fn get_model_cloud_bucket_path() { + let model = default_model(); + let path = VcModel::LegacyVoiceConversion(model).get_model_cloud_bucket_path(&BucketPathUnifier::default_paths()); + assert_eq!(path, PathBuf::from("/user_uploaded_rvc_v2_models/h/a/s/hash.pt")); + } + + #[test] + fn get_index_file_cloud_bucket_path() { + let model = default_model(); + let path = VcModel::LegacyVoiceConversion(model).get_index_file_cloud_bucket_path(&BucketPathUnifier::default_paths()); + assert_eq!(path, None); + + let mut model = default_model(); + model.model_type = VoiceConversionModelType::RvcV2; + model.has_index_file = true; + let path = VcModel::LegacyVoiceConversion(model).get_index_file_cloud_bucket_path(&BucketPathUnifier::default_paths()); + assert_eq!(path, Some(PathBuf::from("/user_uploaded_rvc_v2_models/h/a/s/hash.index"))); + } + + #[test] + fn get_model_type() { + let mut model = default_model(); + model.model_type = VoiceConversionModelType::RvcV2; + assert_eq!(VcModel::LegacyVoiceConversion(model).get_model_type(), VcModelType::RvcV2); + + let mut model = default_model(); + model.model_type = VoiceConversionModelType::SoftVc; + assert_eq!(VcModel::LegacyVoiceConversion(model).get_model_type(), VcModelType::SoftVc); + + let mut model = default_model(); + model.model_type = VoiceConversionModelType::SoVitsSvc; + assert_eq!(VcModel::LegacyVoiceConversion(model).get_model_type(), VcModelType::SoVitsSvc); + } + } + + mod new_model_weights { + use std::path::PathBuf; + + use cloud_storage::bucket_path_unifier::BucketPathUnifier; + use enums::by_table::model_weights::weights_types::WeightsType; + use jobs_common::semi_persistent_cache_dir::SemiPersistentCacheDir; + use mysql_queries::queries::model_weights::inference::get_model_weight_for_voice_conversion_inference::ModelWeightForVoiceConversionInference; + use tokens::tokens::model_weights::ModelWeightToken; + + use crate::job::job_types::vc::vc_model::{VcModel, VcModelType}; + + fn default_model() -> ModelWeightForVoiceConversionInference { + // NB: We could implement/derive the default trait, but this works just as well for now. + ModelWeightForVoiceConversionInference { + token: ModelWeightToken::new_from_str("weight_entropy"), + weights_type: WeightsType::RvcV2, + has_index_file: false, + public_bucket_hash: "hash".to_string(), + maybe_public_bucket_prefix: None, + maybe_public_bucket_extension: None, + title: "title".to_string(), + created_at: Default::default(), + updated_at: Default::default(), + user_deleted_at: None, + mod_deleted_at: None, + } + } + + #[test] + fn has_index_file() { + let mut model = default_model(); + model.has_index_file = false; + model.weights_type = WeightsType::RvcV2; + assert_eq!(VcModel::ModelWeight(model).has_index_file(), false); + + let mut model = default_model(); + model.has_index_file = true; + model.weights_type = WeightsType::RvcV2; + assert_eq!(VcModel::ModelWeight(model).has_index_file(), true); + } + + #[test] + fn get_model_persistent_file_path() { + let model = default_model(); + let path = VcModel::ModelWeight(model).get_model_persistent_filesystem_path(&SemiPersistentCacheDir::default_paths()); + assert_eq!(path, PathBuf::from("/file_cache/voice_conversion/models/weight_entropy.pt")); + } + + #[test] + fn get_model_cloud_bucket_path() { + let model = default_model(); + let path = VcModel::ModelWeight(model).get_model_cloud_bucket_path(&BucketPathUnifier::default_paths()); + assert_eq!(path, PathBuf::from("/weights/h/a/s/hash/file.bin")); + } + + #[test] + fn get_index_file_cloud_bucket_path() { + let model = default_model(); + let path = VcModel::ModelWeight(model).get_index_file_cloud_bucket_path(&BucketPathUnifier::default_paths()); + assert_eq!(path, None); + + let mut model = default_model(); + model.weights_type = WeightsType::RvcV2; + model.has_index_file = true; + let path = VcModel::ModelWeight(model).get_index_file_cloud_bucket_path(&BucketPathUnifier::default_paths()); + assert_eq!(path, Some(PathBuf::from("/weights/h/a/s/hash/hash.rvc_index"))); + } + + #[test] + fn get_model_type() { + let mut model = default_model(); + model.weights_type = WeightsType::RvcV2; + assert_eq!(VcModel::ModelWeight(model).get_model_type(), VcModelType::RvcV2); + + let mut model = default_model(); + model.weights_type = WeightsType::StableDiffusion15; + assert_eq!(VcModel::ModelWeight(model).get_model_type(), VcModelType::Invalid); + + let mut model = default_model(); + model.weights_type = WeightsType::SoVitsSvc; + assert_eq!(VcModel::ModelWeight(model).get_model_type(), VcModelType::SoVitsSvc); + } + } +} \ No newline at end of file From b0df97b2be425c4b3f1528e0829fd9312c75f60b Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Mon, 18 Dec 2023 17:26:41 -0500 Subject: [PATCH 069/124] reuse migration code (+ migration crate) --- Cargo.lock | 27 +++++ Cargo.toml | 1 + .../voice_conversion_to_weights/migrate.rs | 4 +- crates/lib/migration/Cargo.toml | 46 +++++++ crates/lib/migration/src/lib.rs | 20 ++++ .../lib/migration/src/voice_conversion/mod.rs | 1 + .../query_vc_model_for_migration.rs} | 113 ++++++++++++------ crates/service/job/download_job/Cargo.toml | 1 + crates/service/job/inference_job/Cargo.toml | 1 + .../job_loop/determine_dependency_status.rs | 23 ++-- .../inference_job/src/job/job_types/vc/mod.rs | 1 - .../job/job_types/vc/process_single_vc_job.rs | 45 ++----- .../job/job_types/vc/rvc_v2/process_job.rs | 2 +- .../job_types/vc/so_vits_svc/process_job.rs | 2 +- .../job/inference_job/src/job_dependencies.rs | 4 +- crates/service/web/storyteller_web/Cargo.toml | 1 + 16 files changed, 207 insertions(+), 85 deletions(-) create mode 100644 crates/lib/migration/Cargo.toml create mode 100644 crates/lib/migration/src/lib.rs create mode 100644 crates/lib/migration/src/voice_conversion/mod.rs rename crates/{service/job/inference_job/src/job/job_types/vc/vc_model.rs => lib/migration/src/voice_conversion/query_vc_model_for_migration.rs} (87%) diff --git a/Cargo.lock b/Cargo.lock index 10c9daad42..edd67bd242 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1894,6 +1894,7 @@ dependencies = [ "hyper", "jobs_common", "log", + "migration", "mimetypes", "my-workspace-hack", "mysql_queries", @@ -2974,6 +2975,7 @@ dependencies = [ "log", "media", "memory_caching", + "migration", "mime", "mimetypes", "my-workspace-hack", @@ -3481,6 +3483,30 @@ dependencies = [ "my-workspace-hack", ] +[[package]] +name = "migration" +version = "0.0.1" +dependencies = [ + "anyhow", + "buckets", + "chrono", + "cloud_storage", + "enums", + "errors", + "jobs_common", + "my-workspace-hack", + "mysql_queries", + "once_cell", + "serde", + "serde_derive", + "serde_json", + "serial_test", + "sqlx", + "tokens", + "tokio", + "toml 0.5.11", +] + [[package]] name = "migration-tool" version = "0.0.1" @@ -5901,6 +5927,7 @@ dependencies = [ "md-5 0.9.1", "media", "memory_caching", + "migration", "mimetypes", "my-workspace-hack", "mysql_queries", diff --git a/Cargo.toml b/Cargo.toml index 78728f6407..0bd2f6e824 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,6 +49,7 @@ members = [ "crates/lib/idempotency", "crates/lib/jobs_common", "crates/lib/logging", + "crates/lib/migration", "crates/lib/mysql_queries", "crates/lib/password", "crates/lib/redis_common", diff --git a/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/migrate.rs b/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/migrate.rs index 408bc379de..27773e4872 100644 --- a/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/migrate.rs +++ b/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/migrate.rs @@ -1,8 +1,10 @@ use std::thread; use std::time::Duration; + use errors::AnyhowResult; use mysql_queries::queries::model_weights::migration::upsert_model_weight_from_voice_conversion_model::upsert_model_weight_from_voice_conversion_model; -use mysql_queries::queries::voice_conversion::models::list_whole_voice_conversion_models_using_cursor::list_whole_voice_conversion_models_using_cursor; +use mysql_queries::queries::voice_conversion::migration::list_whole_voice_conversion_models_using_cursor::list_whole_voice_conversion_models_using_cursor; + use crate::deps::Deps; const PAGE_SIZE: u64 = 10; diff --git a/crates/lib/migration/Cargo.toml b/crates/lib/migration/Cargo.toml new file mode 100644 index 0000000000..6a61a87189 --- /dev/null +++ b/crates/lib/migration/Cargo.toml @@ -0,0 +1,46 @@ +[package] +name = "migration" +edition = "2018" +version = "0.0.1" +authors = [ + "Brandon Thomas ", + "Brandon Thomas ", +] +publish = false + +[lib] +# NB: Public "migration" crate does not exist, so we're fine to use this internally for a bit. +name = "migration" +path = "src/lib.rs" + +[dependencies] +# Internal +buckets = { path = "../../_types/buckets" } +cloud_storage = { path = "../../lib/api_clients/cloud_storage" } +enums = { path = "../../_types/enums" } +errors = { path = "../../lib/errors" } +jobs_common = { path = "../../lib/jobs_common" } +mysql_queries = { path = "../../lib/mysql_queries" } +tokens = { path = "../../_types/tokens" } + +# External +anyhow = "1.0.75" +chrono = { version = "0.4.22", features = ["serde"] } +once_cell = "1.18.0" + +# Serialization +serde = "1.0.125" +serde_derive = "1.0.125" +serde_json = "1.0.108" +toml = "0.5.8" +serial_test = "2.0.0" + +# Runtime + Clients +tokio = { version = "1.34.0", features = ["full"] } +sqlx = { version = "0.7.2", features = [ "mysql", "runtime-tokio", "tls-rustls", "chrono" ] } + +# Workspace hack (faster compile times) +my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" } + +[dev-dependencies] +# None yet diff --git a/crates/lib/migration/src/lib.rs b/crates/lib/migration/src/lib.rs new file mode 100644 index 0000000000..ecd1e2e7be --- /dev/null +++ b/crates/lib/migration/src/lib.rs @@ -0,0 +1,20 @@ +//! migration +//! +//! This crate should contain short-lived migration utilities for our services. +//! + +// Never allow these +#![forbid(private_in_public)] +#![forbid(unused_must_use)] // NB: It's unsafe to not close/check some things + +// Okay to toggle +#![forbid(unreachable_patterns)] +#![forbid(unused_imports)] +#![forbid(unused_mut)] +#![forbid(unused_variables)] + +// Always allow +#![allow(dead_code)] +#![allow(non_snake_case)] + +pub mod voice_conversion; diff --git a/crates/lib/migration/src/voice_conversion/mod.rs b/crates/lib/migration/src/voice_conversion/mod.rs new file mode 100644 index 0000000000..49389dc658 --- /dev/null +++ b/crates/lib/migration/src/voice_conversion/mod.rs @@ -0,0 +1 @@ +pub mod query_vc_model_for_migration; diff --git a/crates/service/job/inference_job/src/job/job_types/vc/vc_model.rs b/crates/lib/migration/src/voice_conversion/query_vc_model_for_migration.rs similarity index 87% rename from crates/service/job/inference_job/src/job/job_types/vc/vc_model.rs rename to crates/lib/migration/src/voice_conversion/query_vc_model_for_migration.rs index 091fd84f18..901f3aadce 100644 --- a/crates/service/job/inference_job/src/job/job_types/vc/vc_model.rs +++ b/crates/lib/migration/src/voice_conversion/query_vc_model_for_migration.rs @@ -1,15 +1,20 @@ use std::path::PathBuf; +use sqlx::MySqlPool; + use buckets::public::weight_files::bucket_file_path::WeightFileBucketPath; use cloud_storage::bucket_path_unifier::BucketPathUnifier; use enums::by_table::model_weights::weights_types::WeightsType; use enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType; +use errors::AnyhowResult; use jobs_common::semi_persistent_cache_dir::SemiPersistentCacheDir; -use mysql_queries::queries::model_weights::inference::get_model_weight_for_voice_conversion_inference::ModelWeightForVoiceConversionInference; -use mysql_queries::queries::voice_conversion::inference::get_voice_conversion_model_for_inference::VoiceConversionModelForInference; +use mysql_queries::queries::model_weights::inference::get_model_weight_for_voice_conversion_inference::{get_model_weight_for_voice_conversion_inference, ModelWeightForVoiceConversionInference}; +use mysql_queries::queries::voice_conversion::inference::get_voice_conversion_model_for_inference::{get_voice_conversion_model_for_inference, VoiceConversionModelForInference}; +use tokens::tokens::model_weights::ModelWeightToken; /// Union over the legacy table and the new table to support an easier migration. /// This enum can hold a record of either type and present a unified accessor interface. +#[derive(Clone)] pub enum VcModel { /// Old type from the `voice_conversion_models` table, on the way out LegacyVoiceConversion(VoiceConversionModelForInference), @@ -28,6 +33,13 @@ pub enum VcModelType { } impl VcModel { + pub fn get_model_token(&self) -> &str { + match self { + VcModel::LegacyVoiceConversion(ref model) => model.token.as_str(), + VcModel::ModelWeight(ref model) => model.token.as_str(), + } + } + pub fn get_model_type(&self) -> VcModelType { match self { VcModel::LegacyVoiceConversion(ref model) => match model.model_type { @@ -152,6 +164,27 @@ impl VcModel { } } +pub async fn query_vc_model_for_migration(model_token: &str, mysql_pool: &MySqlPool) -> AnyhowResult> { + // NB: This is temporary migration code as we switch from the `voice_conversion_models` table to the `model_weights` table. + if model_token.starts_with(ModelWeightToken::token_prefix()) { + let model_weights_token = ModelWeightToken::new_from_str(model_token); + + let maybe_model = get_model_weight_for_voice_conversion_inference( + &mysql_pool, &model_weights_token).await?; + + Ok(maybe_model + .map(|model| VcModel::ModelWeight(model))) + + } else { + let maybe_vc_model = get_voice_conversion_model_for_inference( + &mysql_pool, model_token).await?; + + Ok(maybe_vc_model + .map(|model| VcModel::LegacyVoiceConversion(model))) + } +} + + #[cfg(test)] mod tests { @@ -164,7 +197,7 @@ mod tests { use mysql_queries::queries::voice_conversion::inference::get_voice_conversion_model_for_inference::VoiceConversionModelForInference; use tokens::tokens::voice_conversion_models::VoiceConversionModelToken; - use crate::job::job_types::vc::vc_model::{VcModel, VcModelType}; + use crate::voice_conversion::query_vc_model_for_migration::{VcModel, VcModelType}; fn default_model() -> VoiceConversionModelForInference { // NB: We could implement/derive the default trait, but this works just as well for now. @@ -181,6 +214,27 @@ mod tests { } } + #[test] + fn get_model_token() { + let model = default_model(); + assert_eq!(VcModel::LegacyVoiceConversion(model).get_model_token(), "vcm_entropy"); + } + + #[test] + fn get_model_type() { + let mut model = default_model(); + model.model_type = VoiceConversionModelType::RvcV2; + assert_eq!(VcModel::LegacyVoiceConversion(model).get_model_type(), VcModelType::RvcV2); + + let mut model = default_model(); + model.model_type = VoiceConversionModelType::SoftVc; + assert_eq!(VcModel::LegacyVoiceConversion(model).get_model_type(), VcModelType::SoftVc); + + let mut model = default_model(); + model.model_type = VoiceConversionModelType::SoVitsSvc; + assert_eq!(VcModel::LegacyVoiceConversion(model).get_model_type(), VcModelType::SoVitsSvc); + } + #[test] fn has_index_file() { let mut model = default_model(); @@ -220,21 +274,6 @@ mod tests { let path = VcModel::LegacyVoiceConversion(model).get_index_file_cloud_bucket_path(&BucketPathUnifier::default_paths()); assert_eq!(path, Some(PathBuf::from("/user_uploaded_rvc_v2_models/h/a/s/hash.index"))); } - - #[test] - fn get_model_type() { - let mut model = default_model(); - model.model_type = VoiceConversionModelType::RvcV2; - assert_eq!(VcModel::LegacyVoiceConversion(model).get_model_type(), VcModelType::RvcV2); - - let mut model = default_model(); - model.model_type = VoiceConversionModelType::SoftVc; - assert_eq!(VcModel::LegacyVoiceConversion(model).get_model_type(), VcModelType::SoftVc); - - let mut model = default_model(); - model.model_type = VoiceConversionModelType::SoVitsSvc; - assert_eq!(VcModel::LegacyVoiceConversion(model).get_model_type(), VcModelType::SoVitsSvc); - } } mod new_model_weights { @@ -246,7 +285,7 @@ mod tests { use mysql_queries::queries::model_weights::inference::get_model_weight_for_voice_conversion_inference::ModelWeightForVoiceConversionInference; use tokens::tokens::model_weights::ModelWeightToken; - use crate::job::job_types::vc::vc_model::{VcModel, VcModelType}; + use crate::voice_conversion::query_vc_model_for_migration::{VcModel, VcModelType}; fn default_model() -> ModelWeightForVoiceConversionInference { // NB: We could implement/derive the default trait, but this works just as well for now. @@ -265,6 +304,27 @@ mod tests { } } + #[test] + fn get_model_token() { + let model = default_model(); + assert_eq!(VcModel::ModelWeight(model).get_model_token(), "weight_entropy"); + } + + #[test] + fn get_model_type() { + let mut model = default_model(); + model.weights_type = WeightsType::RvcV2; + assert_eq!(VcModel::ModelWeight(model).get_model_type(), VcModelType::RvcV2); + + let mut model = default_model(); + model.weights_type = WeightsType::StableDiffusion15; + assert_eq!(VcModel::ModelWeight(model).get_model_type(), VcModelType::Invalid); + + let mut model = default_model(); + model.weights_type = WeightsType::SoVitsSvc; + assert_eq!(VcModel::ModelWeight(model).get_model_type(), VcModelType::SoVitsSvc); + } + #[test] fn has_index_file() { let mut model = default_model(); @@ -304,20 +364,5 @@ mod tests { let path = VcModel::ModelWeight(model).get_index_file_cloud_bucket_path(&BucketPathUnifier::default_paths()); assert_eq!(path, Some(PathBuf::from("/weights/h/a/s/hash/hash.rvc_index"))); } - - #[test] - fn get_model_type() { - let mut model = default_model(); - model.weights_type = WeightsType::RvcV2; - assert_eq!(VcModel::ModelWeight(model).get_model_type(), VcModelType::RvcV2); - - let mut model = default_model(); - model.weights_type = WeightsType::StableDiffusion15; - assert_eq!(VcModel::ModelWeight(model).get_model_type(), VcModelType::Invalid); - - let mut model = default_model(); - model.weights_type = WeightsType::SoVitsSvc; - assert_eq!(VcModel::ModelWeight(model).get_model_type(), VcModelType::SoVitsSvc); - } } } \ No newline at end of file diff --git a/crates/service/job/download_job/Cargo.toml b/crates/service/job/download_job/Cargo.toml index 98ec26fcb2..46a93e5338 100644 --- a/crates/service/job/download_job/Cargo.toml +++ b/crates/service/job/download_job/Cargo.toml @@ -28,6 +28,7 @@ filesys = { path = "../../../lib/files/filesys" } google_drive_common = { path = "../../../lib/api_clients/google_drive_common" } hashing = { path = "../../../lib/files/hashing" } jobs_common = { path = "../../../lib/jobs_common" } +migration = { path = "../../../lib/migration" } mimetypes = { path = "../../../lib/files/mimetypes" } mysql_queries = { path = "../../../lib/mysql_queries" } reusable_types = { path = "../../../_types/reusable_types" } diff --git a/crates/service/job/inference_job/Cargo.toml b/crates/service/job/inference_job/Cargo.toml index cdc9aaf01a..19e17e422b 100644 --- a/crates/service/job/inference_job/Cargo.toml +++ b/crates/service/job/inference_job/Cargo.toml @@ -31,6 +31,7 @@ images = { path = "../../../lib/files/images" } jobs_common = { path = "../../../lib/jobs_common" } media = { path = "../../../lib/files/media" } memory_caching = { path = "../../../lib/caching/memory_caching" } +migration = { path = "../../../lib/migration" } mimetypes = { path = "../../../lib/files/mimetypes" } mysql_queries = { path = "../../../lib/mysql_queries" } redis_common = { path = "../../../lib/redis_common" } diff --git a/crates/service/job/inference_job/src/job/job_loop/determine_dependency_status.rs b/crates/service/job/inference_job/src/job/job_loop/determine_dependency_status.rs index 4d150bc421..65c67f01ca 100644 --- a/crates/service/job/inference_job/src/job/job_loop/determine_dependency_status.rs +++ b/crates/service/job/inference_job/src/job/job_loop/determine_dependency_status.rs @@ -7,6 +7,7 @@ use enums::by_table::generic_inference_jobs::inference_category::InferenceCatego use enums::by_table::tts_models::tts_model_type::TtsModelType; use enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType; use filesys::file_exists::file_exists; +use migration::voice_conversion::query_vc_model_for_migration::{query_vc_model_for_migration, VcModel, VcModelType}; use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob; use mysql_queries::queries::tts::tts_models::get_tts_model_for_inference_improved::{get_tts_model_for_inference_improved, TtsModelForInferenceError, TtsModelForInferenceRecord}; use mysql_queries::queries::voice_conversion::inference::get_voice_conversion_model_for_inference::{get_voice_conversion_model_for_inference, VoiceConversionModelForInference}; @@ -29,7 +30,7 @@ pub struct DependencyStatus { pub enum MaybeInferenceModel { None, TtsModel(TtsModelForInferenceRecord), - VcModel(VoiceConversionModelForInference) + VcModel(VcModel) } pub async fn determine_dependency_status(job_dependencies: &JobDependencies, job: &AvailableInferenceJob) -> Result { @@ -79,19 +80,23 @@ fn get_model_token_and_path(job_dependencies: &JobDependencies, maybe_model: &Ma } } MaybeInferenceModel::VcModel(ref model) => { - match model.model_type { - VoiceConversionModelType::RvcV2 => { + match model.get_model_type() { + VcModelType::RvcV2 => { None // TODO(bt, 2023-07-16): Handle RVCv2. } - VoiceConversionModelType::SoftVc => { + VcModelType::SoftVc => { None } - VoiceConversionModelType::SoVitsSvc => { - maybe_model_token = Some(model.token.to_string()); + VcModelType::SoVitsSvc => { + let token = model.get_model_token(); + maybe_model_token = Some(token.to_string()); Some(job_dependencies .fs .semi_persistent_cache - .voice_conversion_model_path(model.token.as_str())) + .voice_conversion_model_path(token)) + } + VcModelType::Invalid => { + None } } } @@ -157,8 +162,8 @@ async fn get_model_record_from_cacheable_query(job_dependencies: &JobDependencie match maybe_model { Some(model) => MaybeInferenceModel::VcModel(model), None => { - let maybe_vc_model = get_voice_conversion_model_for_inference( - &job_dependencies.db.mysql_pool, token) + let maybe_vc_model = query_vc_model_for_migration(token, + &job_dependencies.db.mysql_pool) .await .map_err(|err| ProcessSingleJobError::Other(anyhow!("database error: {:?}", err)))?; diff --git a/crates/service/job/inference_job/src/job/job_types/vc/mod.rs b/crates/service/job/inference_job/src/job/job_types/vc/mod.rs index dd6ecc5961..c0767e303d 100644 --- a/crates/service/job/inference_job/src/job/job_types/vc/mod.rs +++ b/crates/service/job/inference_job/src/job/job_types/vc/mod.rs @@ -1,4 +1,3 @@ pub mod process_single_vc_job; pub mod rvc_v2; pub mod so_vits_svc; -pub mod vc_model; diff --git a/crates/service/job/inference_job/src/job/job_types/vc/process_single_vc_job.rs b/crates/service/job/inference_job/src/job/job_types/vc/process_single_vc_job.rs index 8de19948a6..14c0d7078b 100644 --- a/crates/service/job/inference_job/src/job/job_types/vc/process_single_vc_job.rs +++ b/crates/service/job/inference_job/src/job/job_types/vc/process_single_vc_job.rs @@ -1,25 +1,16 @@ -use std::time::Duration; - use anyhow::anyhow; use log::{error, info}; -use sqlx::MySqlPool; -use enums::by_table::model_weights::weights_types::WeightsType; -use enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType; -use errors::AnyhowResult; +use migration::voice_conversion::query_vc_model_for_migration::{query_vc_model_for_migration, VcModelType}; use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob; use mysql_queries::queries::media_uploads::get_media_upload_for_inference::get_media_upload_for_inference; -use mysql_queries::queries::model_weights::inference::get_model_weight_for_voice_conversion_inference::{get_model_weight_for_voice_conversion_inference, ModelWeightForVoiceConversionInference}; -use mysql_queries::queries::voice_conversion::inference::get_voice_conversion_model_for_inference::{get_voice_conversion_model_for_inference, VoiceConversionModelForInference}; use tokens::tokens::media_uploads::MediaUploadToken; -use tokens::tokens::model_weights::ModelWeightToken; use crate::job::job_loop::job_success_result::JobSuccessResult; use crate::job::job_loop::process_single_job_error::ProcessSingleJobError; use crate::job::job_types::vc::{rvc_v2, so_vits_svc}; use crate::job::job_types::vc::rvc_v2::process_job::RvcV2ProcessJobArgs; use crate::job::job_types::vc::so_vits_svc::process_job::SoVitsSvcProcessJobArgs; -use crate::job::job_types::vc::vc_model::{VcModel, VcModelType}; use crate::job_dependencies::JobDependencies; pub async fn process_single_vc_job(job_dependencies: &JobDependencies, job: &AvailableInferenceJob) -> Result { @@ -28,7 +19,14 @@ pub async fn process_single_vc_job(job_dependencies: &JobDependencies, job: &Ava None => return Err(ProcessSingleJobError::InvalidJob(anyhow!("No model token for job: {:?}", job.inference_job_token))), }; - let maybe_model = query_model(model_token, &job_dependencies.db.mysql_pool).await?; + // TODO: Interrogate a db result cache + filesystem model file cache + + let maybe_model = query_vc_model_for_migration(model_token, &job_dependencies.db.mysql_pool) + .await + .map_err(|err| { + error!("error querying vc model {model_token} : {:?}", err); + return ProcessSingleJobError::Other(anyhow!("error querying vc model {model_token} : {:?}", err)) + })?; let model = match maybe_model { None => return Err(ProcessSingleJobError::Other(anyhow!("model weights not found: {:?}", model_token))), @@ -106,28 +104,3 @@ pub async fn process_single_vc_job(job_dependencies: &JobDependencies, job: &Ava } -async fn query_model(model_token: &str, mysql_pool: &MySqlPool) -> Result, ProcessSingleJobError> { - // TODO: Interrogate a db result cache + filesystem model file cache - - // NB: This is temporary migration code as we switch from the `voice_conversion_models` table to the `model_weights` table. - if model_token.starts_with(ModelWeightToken::token_prefix()) { - let model_weights_token = ModelWeightToken::new_from_str(model_token); - - let maybe_model = get_model_weight_for_voice_conversion_inference( - &mysql_pool, &model_weights_token) - .await - .map_err(|err| ProcessSingleJobError::Other(anyhow!("database error: {:?}", err)))?; - - Ok(maybe_model - .map(|model| VcModel::ModelWeight(model))) - - } else { - let maybe_vc_model = get_voice_conversion_model_for_inference( - &mysql_pool, model_token) - .await - .map_err(|err| ProcessSingleJobError::Other(anyhow!("database error: {:?}", err)))?; - - Ok(maybe_vc_model - .map(|model| VcModel::LegacyVoiceConversion(model))) - } -} diff --git a/crates/service/job/inference_job/src/job/job_types/vc/rvc_v2/process_job.rs b/crates/service/job/inference_job/src/job/job_types/vc/rvc_v2/process_job.rs index 779366558e..534d52b560 100644 --- a/crates/service/job/inference_job/src/job/job_types/vc/rvc_v2/process_job.rs +++ b/crates/service/job/inference_job/src/job/job_types/vc/rvc_v2/process_job.rs @@ -15,6 +15,7 @@ use filesys::safe_delete_temp_directory::safe_delete_temp_directory; use filesys::safe_delete_temp_file::safe_delete_temp_file; use hashing::sha256::sha256_hash_file::sha256_hash_file; use media::decode_basic_audio_info::decode_basic_audio_file_info; +use migration::voice_conversion::query_vc_model_for_migration::VcModel; use mimetypes::mimetype_for_file::get_mimetype_for_file; use mysql_queries::payloads::generic_inference_args::generic_inference_args::PolymorphicInferenceArgs; use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob; @@ -26,7 +27,6 @@ use tokens::tokens::users::UserToken; use crate::job::job_loop::job_success_result::{JobSuccessResult, ResultEntity}; use crate::job::job_loop::process_single_job_error::ProcessSingleJobError; use crate::job::job_types::vc::rvc_v2::rvc_v2_inference_command::InferenceArgs; -use crate::job::job_types::vc::vc_model::VcModel; use crate::job_dependencies::JobDependencies; use crate::util::maybe_download_file_from_bucket::{maybe_download_file_from_bucket, MaybeDownloadArgs}; diff --git a/crates/service/job/inference_job/src/job/job_types/vc/so_vits_svc/process_job.rs b/crates/service/job/inference_job/src/job/job_types/vc/so_vits_svc/process_job.rs index bb582284e1..82c77cb925 100644 --- a/crates/service/job/inference_job/src/job/job_types/vc/so_vits_svc/process_job.rs +++ b/crates/service/job/inference_job/src/job/job_types/vc/so_vits_svc/process_job.rs @@ -14,6 +14,7 @@ use filesys::safe_delete_temp_directory::safe_delete_temp_directory; use filesys::safe_delete_temp_file::safe_delete_temp_file; use hashing::sha256::sha256_hash_file::sha256_hash_file; use media::decode_basic_audio_info::decode_basic_audio_file_info; +use migration::voice_conversion::query_vc_model_for_migration::VcModel; use mimetypes::mimetype_for_file::get_mimetype_for_file; use mysql_queries::payloads::generic_inference_args::generic_inference_args::PolymorphicInferenceArgs; use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob; @@ -25,7 +26,6 @@ use tokens::tokens::users::UserToken; use crate::job::job_loop::job_success_result::{JobSuccessResult, ResultEntity}; use crate::job::job_loop::process_single_job_error::ProcessSingleJobError; use crate::job::job_types::vc::so_vits_svc::so_vits_svc_inference_command::{Device, InferenceArgs}; -use crate::job::job_types::vc::vc_model::VcModel; use crate::job_dependencies::JobDependencies; use crate::util::maybe_download_file_from_bucket::{maybe_download_file_from_bucket, MaybeDownloadArgs}; diff --git a/crates/service/job/inference_job/src/job_dependencies.rs b/crates/service/job/inference_job/src/job_dependencies.rs index 79d8d703c1..d18dd2c03c 100644 --- a/crates/service/job/inference_job/src/job_dependencies.rs +++ b/crates/service/job/inference_job/src/job_dependencies.rs @@ -18,10 +18,10 @@ use jobs_common::job_stats::JobStats; use jobs_common::semi_persistent_cache_dir::SemiPersistentCacheDir; use memory_caching::multi_item_ttl_cache::MultiItemTtlCache; use memory_caching::ttl_key_counter::TtlKeyCounter; +use migration::voice_conversion::query_vc_model_for_migration::VcModel; use mysql_queries::common_inputs::container_environment_arg::ContainerEnvironmentArg; use mysql_queries::mediators::firehose_publisher::FirehosePublisher; use mysql_queries::queries::tts::tts_models::get_tts_model_for_inference_improved::TtsModelForInferenceRecord; -use mysql_queries::queries::voice_conversion::inference::get_voice_conversion_model_for_inference::VoiceConversionModelForInference; use crate::job_specific_dependencies::JobSpecificDependencies; use crate::util::scoped_execution::ScopedExecution; @@ -164,7 +164,7 @@ pub struct FileSystemDetails { // TODO: Move into the appropriate job-specific dependencies object. pub struct JobCaches { pub tts_model_record_cache: MultiItemTtlCache, - pub vc_model_record_cache: MultiItemTtlCache, + pub vc_model_record_cache: MultiItemTtlCache, /// Skip processing models if they're not on the filesystem. /// If the counter elapses a delta, proceed with calculation. diff --git a/crates/service/web/storyteller_web/Cargo.toml b/crates/service/web/storyteller_web/Cargo.toml index daba92afd2..3746e8dcf1 100644 --- a/crates/service/web/storyteller_web/Cargo.toml +++ b/crates/service/web/storyteller_web/Cargo.toml @@ -38,6 +38,7 @@ hashing = { path = "../../../lib/files/hashing" } http_server_common = { path = "../../../lib/deprecated/http_server_common" } media = { path = "../../../lib/files/media" } memory_caching = { path = "../../../lib/caching/memory_caching" } +migration = { path = "../../../lib/migration" } mimetypes = { path = "../../../lib/files/mimetypes" } mysql_queries = { path = "../../../lib/mysql_queries" } redis_caching = { path = "../../../lib/caching/redis_caching" } From 169b45413d5b573e036ee6f8ce4103ac7d55e78b Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Mon, 18 Dec 2023 20:49:30 -0500 Subject: [PATCH 070/124] port internal model cache --- .../lib/migration/src/voice_conversion/mod.rs | 1 + .../query_vc_model_for_migration.rs | 42 ++-- .../query_vc_model_info_lite_for_migration.rs | 220 ++++++++++++++++++ .../src/queries/model_weights/mod.rs | 1 + .../get_model_weight_info_lite.rs | 63 +++++ .../list_model_weight_info_lite.rs | 45 ++++ .../model_weight_info_lite/mod.rs | 3 + .../model_weight_info_lite.rs | 11 + .../model_info_lite/model_info_lite.rs | 2 +- .../enqueue_voice_conversion_inference.rs | 108 ++++----- .../memory_cache/model_token_to_info_cache.rs | 20 +- .../threads/poll_model_token_info_thread.rs | 136 ++++++++--- 12 files changed, 531 insertions(+), 121 deletions(-) create mode 100644 crates/lib/migration/src/voice_conversion/query_vc_model_info_lite_for_migration.rs create mode 100644 crates/lib/mysql_queries/src/queries/model_weights/model_weight_info_lite/get_model_weight_info_lite.rs create mode 100644 crates/lib/mysql_queries/src/queries/model_weights/model_weight_info_lite/list_model_weight_info_lite.rs create mode 100644 crates/lib/mysql_queries/src/queries/model_weights/model_weight_info_lite/mod.rs create mode 100644 crates/lib/mysql_queries/src/queries/model_weights/model_weight_info_lite/model_weight_info_lite.rs diff --git a/crates/lib/migration/src/voice_conversion/mod.rs b/crates/lib/migration/src/voice_conversion/mod.rs index 49389dc658..1ddf3677ee 100644 --- a/crates/lib/migration/src/voice_conversion/mod.rs +++ b/crates/lib/migration/src/voice_conversion/mod.rs @@ -1 +1,2 @@ pub mod query_vc_model_for_migration; +pub mod query_vc_model_info_lite_for_migration; diff --git a/crates/lib/migration/src/voice_conversion/query_vc_model_for_migration.rs b/crates/lib/migration/src/voice_conversion/query_vc_model_for_migration.rs index 901f3aadce..ad30dc50f3 100644 --- a/crates/lib/migration/src/voice_conversion/query_vc_model_for_migration.rs +++ b/crates/lib/migration/src/voice_conversion/query_vc_model_for_migration.rs @@ -12,6 +12,28 @@ use mysql_queries::queries::model_weights::inference::get_model_weight_for_voice use mysql_queries::queries::voice_conversion::inference::get_voice_conversion_model_for_inference::{get_voice_conversion_model_for_inference, VoiceConversionModelForInference}; use tokens::tokens::model_weights::ModelWeightToken; +/// Query model info +/// Depending on the token prefix, this does either a modern or legacy lookup. +pub async fn query_vc_model_for_migration(model_token: &str, mysql_pool: &MySqlPool) -> AnyhowResult> { + // NB: This is temporary migration code as we switch from the `voice_conversion_models` table to the `model_weights` table. + if model_token.starts_with(ModelWeightToken::token_prefix()) { + let model_weights_token = ModelWeightToken::new_from_str(model_token); + + let maybe_model = get_model_weight_for_voice_conversion_inference( + &mysql_pool, &model_weights_token).await?; + + Ok(maybe_model + .map(|model| VcModel::ModelWeight(model))) + + } else { + let maybe_vc_model = get_voice_conversion_model_for_inference( + &mysql_pool, model_token).await?; + + Ok(maybe_vc_model + .map(|model| VcModel::LegacyVoiceConversion(model))) + } +} + /// Union over the legacy table and the new table to support an easier migration. /// This enum can hold a record of either type and present a unified accessor interface. #[derive(Clone)] @@ -164,26 +186,6 @@ impl VcModel { } } -pub async fn query_vc_model_for_migration(model_token: &str, mysql_pool: &MySqlPool) -> AnyhowResult> { - // NB: This is temporary migration code as we switch from the `voice_conversion_models` table to the `model_weights` table. - if model_token.starts_with(ModelWeightToken::token_prefix()) { - let model_weights_token = ModelWeightToken::new_from_str(model_token); - - let maybe_model = get_model_weight_for_voice_conversion_inference( - &mysql_pool, &model_weights_token).await?; - - Ok(maybe_model - .map(|model| VcModel::ModelWeight(model))) - - } else { - let maybe_vc_model = get_voice_conversion_model_for_inference( - &mysql_pool, model_token).await?; - - Ok(maybe_vc_model - .map(|model| VcModel::LegacyVoiceConversion(model))) - } -} - #[cfg(test)] mod tests { diff --git a/crates/lib/migration/src/voice_conversion/query_vc_model_info_lite_for_migration.rs b/crates/lib/migration/src/voice_conversion/query_vc_model_info_lite_for_migration.rs new file mode 100644 index 0000000000..8912dfd5c7 --- /dev/null +++ b/crates/lib/migration/src/voice_conversion/query_vc_model_info_lite_for_migration.rs @@ -0,0 +1,220 @@ +use sqlx::{MySql, MySqlPool}; +use sqlx::pool::PoolConnection; + +use enums::by_table::generic_inference_jobs::inference_category::InferenceCategory; +use enums::by_table::generic_inference_jobs::inference_model_type::InferenceModelType; +use enums::by_table::model_weights::weights_types::WeightsType; +use enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType; +use errors::AnyhowResult; +use mysql_queries::queries::model_weights::model_weight_info_lite::get_model_weight_info_lite::get_model_weight_info_lite_with_connection; +use mysql_queries::queries::model_weights::model_weight_info_lite::model_weight_info_lite::ModelWeightInfoLite; +use mysql_queries::queries::voice_conversion::model_info_lite::get_voice_conversion_model_info_lite::get_voice_conversion_model_info_lite_with_connection; +use mysql_queries::queries::voice_conversion::model_info_lite::model_info_lite::VoiceConversionModelInfoLite; +use tokens::tokens::model_weights::ModelWeightToken; + +/// Query "light info" for models. +/// This is typically used for in-memory token-to-type caches. +pub async fn query_vc_model_info_lite_for_migration(model_token: &str, mysql_pool: &MySqlPool) -> AnyhowResult> { + let mut connection = mysql_pool.acquire().await?; + query_vc_model_info_lite_for_migration_with_connection(model_token, &mut connection).await +} + +/// Query "light info" for models. +/// This is typically used for in-memory token-to-type caches. +pub async fn query_vc_model_info_lite_for_migration_with_connection( + model_token: &str, + mysql_connection: &mut PoolConnection +) -> AnyhowResult> { + // NB: This is temporary migration code as we switch from the `voice_conversion_models` table to the `model_weights` table. + if model_token.starts_with(ModelWeightToken::token_prefix()) { + let model_weights_token = ModelWeightToken::new_from_str(model_token); + + let maybe_model = get_model_weight_info_lite_with_connection( + &model_weights_token, mysql_connection).await?; + + Ok(maybe_model.map(|model| VcModelLite::ModelWeight(model))) + + } else { + let maybe_vc_model = get_voice_conversion_model_info_lite_with_connection( + model_token, mysql_connection).await?; + + Ok(maybe_vc_model.map(|model| VcModelLite::LegacyVoiceConversion(model))) + } +} + + +/// Union over the legacy table and the new table to support an easier migration. +/// This enum can hold a record of either type and present a unified accessor interface. +#[derive(Clone, Debug)] +pub enum VcModelLite { + /// Old type from the `voice_conversion_models` table, on the way out + LegacyVoiceConversion(VoiceConversionModelInfoLite), + /// New type, replacing the `voice_conversion_models` table. + ModelWeight(ModelWeightInfoLite), +} + +impl VcModelLite { + pub fn get_model_token(&self) -> &str { + match self { + VcModelLite::LegacyVoiceConversion(ref model) => model.token.as_str(), + VcModelLite::ModelWeight(ref model) => model.token.as_str(), + } + } + + pub fn get_inference_category(&self) -> Option { + match self { + VcModelLite::LegacyVoiceConversion(ref model) => match model.model_type { + VoiceConversionModelType::RvcV2 => Some(InferenceCategory::VoiceConversion), + VoiceConversionModelType::SoftVc => Some(InferenceCategory::VoiceConversion), + VoiceConversionModelType::SoVitsSvc => Some(InferenceCategory::VoiceConversion), + } + VcModelLite::ModelWeight(ref model) => match model.weights_type { + WeightsType::SoVitsSvc => Some(InferenceCategory::VoiceConversion), + WeightsType::RvcV2 => Some(InferenceCategory::VoiceConversion), + WeightsType::Tacotron2 => Some(InferenceCategory::TextToSpeech), + WeightsType::StableDiffusion15 => None, // TODO(bt,2023-12-18): New category for image generation + WeightsType::StableDiffusionXL => None, // TODO(bt,2023-12-18): New category for image generation + WeightsType::HifiganTacotron2 => None, // NB: Not used directly in inference. Included by other models. + WeightsType::LoRA => None, // NB: not used directly in inference. Included in other models. + WeightsType::VallE => None, // TODO(bt,2023-12-18): Does this mean speaker weights? + } + } + } + + pub fn get_inference_model_type(&self) -> Option { + match self { + VcModelLite::LegacyVoiceConversion(ref model) => match model.model_type { + VoiceConversionModelType::RvcV2 => Some(InferenceModelType::RvcV2), + VoiceConversionModelType::SoftVc => None, // NB: Not supported. + VoiceConversionModelType::SoVitsSvc => Some(InferenceModelType::SoVitsSvc), + } + VcModelLite::ModelWeight(ref model) => match model.weights_type { + WeightsType::SoVitsSvc => Some(InferenceModelType::SoVitsSvc), + WeightsType::RvcV2 => Some(InferenceModelType::RvcV2), + WeightsType::Tacotron2 => Some(InferenceModelType::Tacotron2), + WeightsType::StableDiffusion15 => None, // TODO(bt, 2023-12-18): New model type for image generation + WeightsType::StableDiffusionXL => None, // TODO(bt, 2023-12-18): New model type for image generation + WeightsType::HifiganTacotron2 => None, // NB: Not used directly in inference. Included by other models. + WeightsType::LoRA => None, // NB: not used directly in inference. Included in other models. + WeightsType::VallE => None, // TODO(bt,2023-12-18): Does this mean speaker weights? + } + } + } +} + + +#[cfg(test)] +mod tests { + + mod legacy_voice_conversion_models { + use enums::by_table::generic_inference_jobs::inference_category::InferenceCategory; + use enums::by_table::generic_inference_jobs::inference_model_type::InferenceModelType; + use enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType; + use mysql_queries::queries::voice_conversion::model_info_lite::model_info_lite::VoiceConversionModelInfoLite; + use tokens::tokens::voice_conversion_models::VoiceConversionModelToken; + + use crate::voice_conversion::query_vc_model_info_lite_for_migration::VcModelLite; + + fn default_model() -> VoiceConversionModelInfoLite { + // NB: We could implement/derive the default trait, but this works just as well for now. + VoiceConversionModelInfoLite { + token: VoiceConversionModelToken::new_from_str("vcm_entropy"), + model_type: VoiceConversionModelType::RvcV2, + } + } + + #[test] + fn get_model_token() { + let model = default_model(); + assert_eq!(VcModelLite::LegacyVoiceConversion(model).get_model_token(), "vcm_entropy"); + } + + #[test] + fn get_inference_category() { + let mut model = default_model(); + model.model_type = VoiceConversionModelType::RvcV2; + assert_eq!(VcModelLite::LegacyVoiceConversion(model).get_inference_category(), Some(InferenceCategory::VoiceConversion)); + + let mut model = default_model(); + model.model_type = VoiceConversionModelType::SoVitsSvc; + assert_eq!(VcModelLite::LegacyVoiceConversion(model).get_inference_category(), Some(InferenceCategory::VoiceConversion)); + + let mut model = default_model(); + model.model_type = VoiceConversionModelType::SoftVc; + assert_eq!(VcModelLite::LegacyVoiceConversion(model).get_inference_category(), Some(InferenceCategory::VoiceConversion)); + } + + #[test] + fn get_inference_model_type() { + let mut model = default_model(); + model.model_type = VoiceConversionModelType::RvcV2; + assert_eq!(VcModelLite::LegacyVoiceConversion(model).get_inference_model_type(), Some(InferenceModelType::RvcV2)); + + let mut model = default_model(); + model.model_type = VoiceConversionModelType::SoVitsSvc; + assert_eq!(VcModelLite::LegacyVoiceConversion(model).get_inference_model_type(), Some(InferenceModelType::SoVitsSvc)); + + let mut model = default_model(); + model.model_type = VoiceConversionModelType::SoftVc; + assert_eq!(VcModelLite::LegacyVoiceConversion(model).get_inference_model_type(), None); + } + } + + mod new_model_weights { + use enums::by_table::generic_inference_jobs::inference_category::InferenceCategory; + use enums::by_table::generic_inference_jobs::inference_model_type::InferenceModelType; + use enums::by_table::model_weights::weights_types::WeightsType; + use mysql_queries::queries::model_weights::model_weight_info_lite::model_weight_info_lite::ModelWeightInfoLite; + use tokens::tokens::model_weights::ModelWeightToken; + + use crate::voice_conversion::query_vc_model_info_lite_for_migration::VcModelLite; + + fn default_model() -> ModelWeightInfoLite { + // NB: We could implement/derive the default trait, but this works just as well for now. + ModelWeightInfoLite { + token: ModelWeightToken::new_from_str("weight_entropy"), + weights_type: WeightsType::RvcV2, + } + } + + #[test] + fn get_model_token() { + let model = default_model(); + assert_eq!(VcModelLite::ModelWeight(model).get_model_token(), "weight_entropy"); + } + + #[test] + fn get_inference_category() { + let mut model = default_model(); + model.weights_type = WeightsType::RvcV2; + assert_eq!(VcModelLite::ModelWeight(model).get_inference_category(), Some(InferenceCategory::VoiceConversion)); + + let mut model = default_model(); + model.weights_type = WeightsType::SoVitsSvc; + assert_eq!(VcModelLite::ModelWeight(model).get_inference_category(), Some(InferenceCategory::VoiceConversion)); + + let mut model = default_model(); + model.weights_type = WeightsType::Tacotron2; + assert_eq!(VcModelLite::ModelWeight(model).get_inference_category(), Some(InferenceCategory::TextToSpeech)); + + let mut model = default_model(); + model.weights_type = WeightsType::StableDiffusion15; + assert_eq!(VcModelLite::ModelWeight(model).get_inference_category(), None); + } + + #[test] + fn get_inference_model_type() { + let mut model = default_model(); + model.weights_type = WeightsType::RvcV2; + assert_eq!(VcModelLite::ModelWeight(model).get_inference_model_type(), Some(InferenceModelType::RvcV2)); + + let mut model = default_model(); + model.weights_type = WeightsType::SoVitsSvc; + assert_eq!(VcModelLite::ModelWeight(model).get_inference_model_type(), Some(InferenceModelType::SoVitsSvc)); + + let mut model = default_model(); + model.weights_type = WeightsType::StableDiffusion15; + assert_eq!(VcModelLite::ModelWeight(model).get_inference_model_type(), None); + } + } +} diff --git a/crates/lib/mysql_queries/src/queries/model_weights/mod.rs b/crates/lib/mysql_queries/src/queries/model_weights/mod.rs index fd09bc5721..62ad3e22fa 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/mod.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/mod.rs @@ -9,3 +9,4 @@ pub mod list_weights_query_builder; pub mod migration; pub mod tests; pub mod update_weight; +pub mod model_weight_info_lite; diff --git a/crates/lib/mysql_queries/src/queries/model_weights/model_weight_info_lite/get_model_weight_info_lite.rs b/crates/lib/mysql_queries/src/queries/model_weights/model_weight_info_lite/get_model_weight_info_lite.rs new file mode 100644 index 0000000000..7bb4b8ed56 --- /dev/null +++ b/crates/lib/mysql_queries/src/queries/model_weights/model_weight_info_lite/get_model_weight_info_lite.rs @@ -0,0 +1,63 @@ +use anyhow::anyhow; +use log::warn; +use sqlx::{MySql, MySqlPool}; +use sqlx::pool::PoolConnection; + +use enums::by_table::model_weights::weights_types::WeightsType; +use errors::AnyhowResult; +use tokens::tokens::model_weights::ModelWeightToken; + +use crate::queries::model_weights::model_weight_info_lite::model_weight_info_lite::ModelWeightInfoLite; + +pub async fn get_model_weight_info_lite( + token: &ModelWeightToken, + mysql_pool: &MySqlPool, +) -> AnyhowResult> { + let mut connection = mysql_pool.acquire().await?; + get_model_weight_info_lite_with_connection(token, &mut connection).await +} + +pub async fn get_model_weight_info_lite_with_connection( + token: &ModelWeightToken, + mysql_connection: &mut PoolConnection, +) -> AnyhowResult> { + + let maybe_model= sqlx::query_as!( + RawModelWeightInfoLite, + r#" +SELECT + m.token as `token: tokens::tokens::model_weights::ModelWeightToken`, + m.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType` +FROM model_weights as m +WHERE m.token = ? + "#, + token + ) + .fetch_one(&mut **mysql_connection) + .await; + + let model : RawModelWeightInfoLite = match maybe_model { + Ok(model) => model, + Err(err) => { + return match err { + sqlx::Error::RowNotFound => { + Ok(None) + }, + _ => { + warn!("error querying model weight info lite: {:?}", err); + Err(anyhow!("error querying model weight info lite: {:?}", err)) + } + } + } + }; + + Ok(Some(ModelWeightInfoLite { + token: model.token, + weights_type: model.weights_type, + })) +} + +struct RawModelWeightInfoLite { + pub token: ModelWeightToken, + pub weights_type: WeightsType, +} diff --git a/crates/lib/mysql_queries/src/queries/model_weights/model_weight_info_lite/list_model_weight_info_lite.rs b/crates/lib/mysql_queries/src/queries/model_weights/model_weight_info_lite/list_model_weight_info_lite.rs new file mode 100644 index 0000000000..82c79c5038 --- /dev/null +++ b/crates/lib/mysql_queries/src/queries/model_weights/model_weight_info_lite/list_model_weight_info_lite.rs @@ -0,0 +1,45 @@ +use sqlx::{MySql, MySqlPool}; +use sqlx::pool::PoolConnection; + +use enums::by_table::model_weights::weights_types::WeightsType; +use errors::AnyhowResult; +use tokens::tokens::model_weights::ModelWeightToken; + +use crate::queries::model_weights::model_weight_info_lite::model_weight_info_lite::ModelWeightInfoLite; + +pub async fn list_model_weight_info_lite( + mysql_pool: &MySqlPool, +) -> AnyhowResult> { + let mut connection = mysql_pool.acquire().await?; + list_model_weight_info_lite_with_connection(&mut connection).await +} + +pub async fn list_model_weight_info_lite_with_connection( + mysql_connection: &mut PoolConnection, +) -> AnyhowResult> { + + let models = sqlx::query_as!( + RawModelWeightsInfoLite, + r#" +SELECT + w.token as `token: tokens::tokens::model_weights::ModelWeightToken`, + w.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType` +FROM model_weights as w + "#) + .fetch_all(&mut **mysql_connection) + .await?; + + Ok(models.into_iter() + .map(|model| { + ModelWeightInfoLite { + token: model.token, + weights_type: model.weights_type, + } + }) + .collect::>()) +} + +struct RawModelWeightsInfoLite { + pub token: ModelWeightToken, + pub weights_type: WeightsType, +} diff --git a/crates/lib/mysql_queries/src/queries/model_weights/model_weight_info_lite/mod.rs b/crates/lib/mysql_queries/src/queries/model_weights/model_weight_info_lite/mod.rs new file mode 100644 index 0000000000..77f8c59a18 --- /dev/null +++ b/crates/lib/mysql_queries/src/queries/model_weights/model_weight_info_lite/mod.rs @@ -0,0 +1,3 @@ +pub mod get_model_weight_info_lite; +pub mod list_model_weight_info_lite; +pub mod model_weight_info_lite; \ No newline at end of file diff --git a/crates/lib/mysql_queries/src/queries/model_weights/model_weight_info_lite/model_weight_info_lite.rs b/crates/lib/mysql_queries/src/queries/model_weights/model_weight_info_lite/model_weight_info_lite.rs new file mode 100644 index 0000000000..86bff567cf --- /dev/null +++ b/crates/lib/mysql_queries/src/queries/model_weights/model_weight_info_lite/model_weight_info_lite.rs @@ -0,0 +1,11 @@ +use enums::by_table::model_weights::weights_types::WeightsType; +use tokens::tokens::model_weights::ModelWeightToken; + +/// This is meant to be used for quick in-memory caches, particularly ones that +/// serve the inference enqueue APIs and check for model existence/validity. +/// The web service can quickly know which model types are valid for which inference types. +#[derive(Serialize, Clone, Debug)] +pub struct ModelWeightInfoLite { + pub token: ModelWeightToken, + pub weights_type: WeightsType, +} diff --git a/crates/lib/mysql_queries/src/queries/voice_conversion/model_info_lite/model_info_lite.rs b/crates/lib/mysql_queries/src/queries/voice_conversion/model_info_lite/model_info_lite.rs index a95522f64b..e11e478e96 100644 --- a/crates/lib/mysql_queries/src/queries/voice_conversion/model_info_lite/model_info_lite.rs +++ b/crates/lib/mysql_queries/src/queries/voice_conversion/model_info_lite/model_info_lite.rs @@ -3,7 +3,7 @@ use tokens::tokens::voice_conversion_models::VoiceConversionModelToken; /// This is meant to be used for quick in-memory caches, /// particularly the one that serves the voice conversion enqueue API. -#[derive(Serialize)] +#[derive(Serialize, Clone, Debug)] pub struct VoiceConversionModelInfoLite { pub token: VoiceConversionModelToken, pub model_type: VoiceConversionModelType, diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_conversion/inference/enqueue_voice_conversion_inference.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_conversion/inference/enqueue_voice_conversion_inference.rs index 7be7cec00d..5d9605c9bf 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_conversion/inference/enqueue_voice_conversion_inference.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_conversion/inference/enqueue_voice_conversion_inference.rs @@ -17,24 +17,22 @@ use sqlx::pool::PoolConnection; use enums::by_table::generic_inference_jobs::inference_category::InferenceCategory; use enums::by_table::generic_inference_jobs::inference_input_source_token_type::InferenceInputSourceTokenType; use enums::by_table::generic_inference_jobs::inference_model_type::InferenceModelType; -use enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType; use enums::common::visibility::Visibility; use http_server_common::request::get_request_header_optional::get_request_header_optional; use http_server_common::request::get_request_ip::get_request_ip; +use migration::voice_conversion::query_vc_model_info_lite_for_migration::query_vc_model_info_lite_for_migration_with_connection; use mysql_queries::payloads::generic_inference_args::generic_inference_args::{FundamentalFrequencyMethodForJob, GenericInferenceArgs, InferenceCategoryAbbreviated, PolymorphicInferenceArgs}; use mysql_queries::queries::generic_inference::web::insert_generic_inference_job::{insert_generic_inference_job, InsertGenericInferenceArgs}; -use mysql_queries::queries::voice_conversion::model_info_lite::get_voice_conversion_model_info_lite::get_voice_conversion_model_info_lite_with_connection; use redis_common::redis_keys::RedisKeys; use tokens::tokens::generic_inference_jobs::InferenceJobToken; use tokens::tokens::media_uploads::MediaUploadToken; use tokens::tokens::users::UserToken; -use tokens::tokens::voice_conversion_models::VoiceConversionModelToken; use tts_common::priority::FAKEYOU_INVESTOR_PRIORITY_LEVEL; use crate::configs::plans::get_correct_plan_for_session::get_correct_plan_for_session; use crate::http_server::endpoints::investor_demo::demo_cookie::request_has_demo_cookie; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; -use crate::memory_cache::model_token_to_info_cache::{ModelInfoLite, ModelTokenToInfoCache}; +use crate::memory_cache::model_token_to_info_cache::{ModelInfoForInferenceJob, ModelTokenToInfoCache}; use crate::server_state::ServerState; /// Debug requests can get routed to special "debug-only" workers, which can @@ -48,7 +46,7 @@ const ROUTING_TAG_HEADER_NAME : &str = "routing-tag"; #[derive(Deserialize)] pub struct EnqueueVoiceConversionInferenceRequest { uuid_idempotency_token: String, - voice_conversion_model_token: VoiceConversionModelToken, + voice_conversion_model_token: String, // TODO: Make media upload token optional and allow result audio to be re-used as well source_media_upload_token: MediaUploadToken, @@ -237,7 +235,7 @@ pub async fn enqueue_voice_conversion_inference_handler( let model_token = request.voice_conversion_model_token.clone(); let media_token = request.source_media_upload_token.clone(); - let model_info_lite = lookup_model_info( + let model_inference_info = lookup_model_info( &model_token, &server_state.caches.durable.model_token_info, &mut mysql_connection @@ -252,7 +250,7 @@ pub async fn enqueue_voice_conversion_inference_handler( EnqueueVoiceConversionInferenceError::ServerError })?; - let redis_count_key = RedisKeys::web_vc_model_usage_count(model_token.as_str()); + let redis_count_key = RedisKeys::web_vc_model_usage_count(&model_token); redis.incr(&redis_count_key, 1) .map_err(|e| { @@ -270,7 +268,6 @@ pub async fn enqueue_voice_conversion_inference_handler( .or(maybe_user_preferred_visibility) .unwrap_or(Visibility::Public); - info!("Creating voice conversion inference job record..."); let mut maybe_args = None; @@ -295,8 +292,8 @@ pub async fn enqueue_voice_conversion_inference_handler( let query_result = insert_generic_inference_job(InsertGenericInferenceArgs { uuid_idempotency_token: &request.uuid_idempotency_token, inference_category: InferenceCategory::VoiceConversion, - maybe_model_type: Some(model_info_lite.model_type), - maybe_model_token: Some(model_token.as_str()), + maybe_model_type: Some(model_inference_info.job_model_type), + maybe_model_token: Some(&model_token), maybe_input_source_token: Some(media_token.as_str()), maybe_input_source_token_type: Some(InferenceInputSourceTokenType::MediaUpload), maybe_raw_inference_text: None, // NB: Voice conversion isn't TTS, so there's no text. @@ -347,62 +344,59 @@ pub async fn enqueue_voice_conversion_inference_handler( } async fn lookup_model_info( - model_token: &VoiceConversionModelToken, + model_token: &str, cache: &ModelTokenToInfoCache, mysql_connection: &mut PoolConnection, -) -> Result { - let maybe_model_token_info = cache - .get_info(model_token.as_str()) +) -> Result { + let maybe_model_inference_info = cache + .get_info(model_token) .map_err(|err| { error!("in-memory cache error: {:?}", err); EnqueueVoiceConversionInferenceError::ServerError })?; - let model_token_info = match maybe_model_token_info { - Some(info) => info, + if let Some(inference_info) = maybe_model_inference_info { + return Ok(inference_info); + } + + let result = query_vc_model_info_lite_for_migration_with_connection( + model_token, mysql_connection) + .await + .map_err(|err| { + error!("model lookup error: {:?}", err); + EnqueueVoiceConversionInferenceError::ServerError + })?; + + let model_info = match result { + Some(model_info) => model_info, None => { - let result = get_voice_conversion_model_info_lite_with_connection( - model_token.as_str(), mysql_connection) - .await - .map_err(|err| { - error!("model lookup error: {:?}", err); - EnqueueVoiceConversionInferenceError::ServerError - })?; - - match result { - Some(info) => { - let model_type = match info.model_type { - VoiceConversionModelType::RvcV2 => InferenceModelType::RvcV2, - VoiceConversionModelType::SoVitsSvc => InferenceModelType::SoVitsSvc, - VoiceConversionModelType::SoftVc => { - // SoftVC is unsupported - return Err(EnqueueVoiceConversionInferenceError::BadInput("wrong model type".to_string())); - } - }; - - let model_info = ModelInfoLite { - inference_category: InferenceCategory::VoiceConversion, - model_type, - }; - - cache.insert_one(model_token.as_str(), &model_info) - .map_err(|err| { - error!("cache insertion error: {:?}", err); - EnqueueVoiceConversionInferenceError::ServerError - })?; - - model_info - } - None => { - // NB: Fail open for now. - ModelInfoLite { - inference_category: InferenceCategory::VoiceConversion, - model_type: InferenceModelType::SoVitsSvc, - } - } - } + warn!("model not found for {model_token}; failing open"); + // NB: Fail open for now. + return Ok(ModelInfoForInferenceJob { + job_inference_category: InferenceCategory::VoiceConversion, + job_model_type: InferenceModelType::SoVitsSvc, + }); } }; - Ok(model_token_info) + let inference_info = match (model_info.get_inference_category(), model_info.get_inference_model_type()) { + (Some(inference_category), Some(model_type)) => { + ModelInfoForInferenceJob { + job_inference_category: inference_category, + job_model_type: model_type, + } + } + _ => { + error!("wrong model type for inference: {:?}", model_info); + return Err(EnqueueVoiceConversionInferenceError::BadInput("wrong model type for inference".to_string())); + } + }; + + cache.insert_one(model_token, &inference_info) + .map_err(|err| { + error!("cache insertion error: {:?}", err); + EnqueueVoiceConversionInferenceError::ServerError + })?; + + Ok(inference_info) } diff --git a/crates/service/web/storyteller_web/src/memory_cache/model_token_to_info_cache.rs b/crates/service/web/storyteller_web/src/memory_cache/model_token_to_info_cache.rs index 70cea83da4..022e453f7a 100644 --- a/crates/service/web/storyteller_web/src/memory_cache/model_token_to_info_cache.rs +++ b/crates/service/web/storyteller_web/src/memory_cache/model_token_to_info_cache.rs @@ -7,17 +7,21 @@ use enums::by_table::generic_inference_jobs::inference_category::InferenceCatego use enums::by_table::generic_inference_jobs::inference_model_type::InferenceModelType; use errors::AnyhowResult; -#[derive(Clone)] -pub struct ModelInfoLite { - pub inference_category: InferenceCategory, - pub model_type: InferenceModelType, +/// Associate model tokens with these to know immediately what metadata to populate an inference job with. +/// This will prevent having to look up the model record directly upon enqueue. +#[derive(Clone, Debug)] +pub struct ModelInfoForInferenceJob { + /// Which inference category the model token falls under. + pub job_inference_category: InferenceCategory, + /// Which model type the model token falls under. + pub job_model_type: InferenceModelType, } /// Model token to type will never change, so we can cache them indefinitely. /// This is for generic inference jobs only. #[derive(Clone)] pub struct ModelTokenToInfoCache { - database: Arc>>, + database: Arc>>, } impl ModelTokenToInfoCache { @@ -27,7 +31,7 @@ impl ModelTokenToInfoCache { } } - pub fn insert_one(&self, token: &str, info: &ModelInfoLite) -> AnyhowResult<()> { + pub fn insert_one(&self, token: &str, info: &ModelInfoForInferenceJob) -> AnyhowResult<()> { match self.database.write() { Err(err) => return Err(anyhow!("lock err: {:?}", err)), Ok(mut lock) => { @@ -37,7 +41,7 @@ impl ModelTokenToInfoCache { Ok(()) } - pub fn insert_many(&self, records: Vec<(String, ModelInfoLite)>) -> AnyhowResult<()> { + pub fn insert_many(&self, records: Vec<(String, ModelInfoForInferenceJob)>) -> AnyhowResult<()> { match self.database.write() { Err(err) => return Err(anyhow!("lock err: {:?}", err)), Ok(mut lock) => { @@ -49,7 +53,7 @@ impl ModelTokenToInfoCache { Ok(()) } - pub fn get_info(&self, token: &str) -> AnyhowResult> { + pub fn get_info(&self, token: &str) -> AnyhowResult> { match self.database.read() { Err(err) => Err(anyhow!("lock err: {:?}", err)), Ok(lock) => { diff --git a/crates/service/web/storyteller_web/src/threads/poll_model_token_info_thread.rs b/crates/service/web/storyteller_web/src/threads/poll_model_token_info_thread.rs index 940736037c..c7dc38515f 100644 --- a/crates/service/web/storyteller_web/src/threads/poll_model_token_info_thread.rs +++ b/crates/service/web/storyteller_web/src/threads/poll_model_token_info_thread.rs @@ -5,10 +5,13 @@ use sqlx::MySqlPool; use enums::by_table::generic_inference_jobs::inference_category::InferenceCategory; use enums::by_table::generic_inference_jobs::inference_model_type::InferenceModelType; +use enums::by_table::model_weights::weights_types::WeightsType; use enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType; +use errors::AnyhowResult; +use mysql_queries::queries::model_weights::model_weight_info_lite::list_model_weight_info_lite::list_model_weight_info_lite; use mysql_queries::queries::voice_conversion::model_info_lite::list_voice_conversion_model_info_lite::list_voice_conversion_model_info_lite; -use crate::memory_cache::model_token_to_info_cache::{ModelInfoLite, ModelTokenToInfoCache}; +use crate::memory_cache::model_token_to_info_cache::{ModelInfoForInferenceJob, ModelTokenToInfoCache}; pub async fn poll_model_token_info_thread( model_token_info_cache: ModelTokenToInfoCache, @@ -17,49 +20,49 @@ pub async fn poll_model_token_info_thread( let startup_wait = easyenv::get_env_duration_seconds_or_default( "POLL_MODEL_TOKEN_STARTUP_WAIT_DURATION_SECS", Duration::from_secs(5)); + let between_wait = easyenv::get_env_duration_seconds_or_default( + "POLL_MODEL_TOKEN_BETWEEN_WAIT_DURATION_SECS", Duration::from_secs(2)); + + let error_wait = easyenv::get_env_duration_seconds_or_default( + "POLL_MODEL_TOKEN_ERROR_WAIT_DURATION_SECS", Duration::from_secs(60)); + let interval_wait = easyenv::get_env_duration_seconds_or_default( "POLL_MODEL_TOKEN_INTERVAL_SECS", Duration::from_secs(10 * 60)); std::thread::sleep(startup_wait); - // TODO(bt,2023-07-23): This only handles voice conversion models for now. - // We should pick up TTS models when they run on this job system - loop { - debug!("Job fetching token info..."); - - let token_infos= - match list_voice_conversion_model_info_lite(&mysql_pool).await { - Ok(infos) => infos, - Err(err) => { - error!("Error polling model token info: {:?}", err); - std::thread::sleep(interval_wait); - continue; - } - }; - - let mut token_info_items = Vec::with_capacity(token_infos.len()); - - for token_info in token_infos.into_iter() { - let model_type = match token_info.model_type { - VoiceConversionModelType::RvcV2 => InferenceModelType::RvcV2, - VoiceConversionModelType::SoVitsSvc => InferenceModelType::SoVitsSvc, - VoiceConversionModelType::SoftVc => { - continue // NB: SoftVC is not supported. - }, - }; - - let info = ModelInfoLite { - inference_category: InferenceCategory::VoiceConversion, - model_type, - }; - - token_info_items.push((token_info.token.to_string(), info)); - } + let token_info_items = match query_voice_conversion_models(&mysql_pool).await { + Ok(infos) => infos, + Err(err) => { + error!("Error polling voice conversion model token info: {:?}", err); + std::thread::sleep(error_wait); + continue; + } + }; let database_count = token_info_items.len(); - info!("Job found {} token info items from database.", database_count); + info!("Job found {} model token info items from database.", database_count); + + if let Err(err) = model_token_info_cache.insert_many(token_info_items) { + error!("Error inserting model token info: {:?}", err); + } + + std::thread::sleep(between_wait); + + let token_info_items = match query_model_weight_models(&mysql_pool).await { + Ok(infos) => infos, + Err(err) => { + error!("Error polling model weight token info: {:?}", err); + std::thread::sleep(error_wait); + continue; + } + }; + + let database_count = token_info_items.len(); + + info!("Job found {} model token info items from database.", database_count); if let Err(err) = model_token_info_cache.insert_many(token_info_items) { error!("Error inserting model token info: {:?}", err); @@ -68,3 +71,66 @@ pub async fn poll_model_token_info_thread( std::thread::sleep(interval_wait); } } + +async fn query_voice_conversion_models(mysql_pool: &MySqlPool) + -> AnyhowResult> +{ + debug!("Job fetching voice conversion model token info..."); + + let token_infos = + list_voice_conversion_model_info_lite(&mysql_pool).await?; + + let mut token_info_items = Vec::with_capacity(token_infos.len()); + + for token_info in token_infos.into_iter() { + let model_type = match token_info.model_type { + VoiceConversionModelType::RvcV2 => InferenceModelType::RvcV2, + VoiceConversionModelType::SoVitsSvc => InferenceModelType::SoVitsSvc, + VoiceConversionModelType::SoftVc => { + continue // NB: SoftVC is not supported. + }, + }; + + let info = ModelInfoForInferenceJob { + job_inference_category: InferenceCategory::VoiceConversion, + job_model_type: model_type, + }; + + token_info_items.push((token_info.token.to_string(), info)); + } + + Ok(token_info_items) +} + +async fn query_model_weight_models(mysql_pool: &MySqlPool) + -> AnyhowResult> +{ + debug!("Job fetching model weight token info..."); + + let token_infos = + list_model_weight_info_lite(&mysql_pool).await?; + + let mut token_info_items = Vec::with_capacity(token_infos.len()); + + for token_info in token_infos.into_iter() { + let (inference_category, inference_model_type) = match token_info.weights_type { + WeightsType::RvcV2 => (InferenceCategory::VoiceConversion, InferenceModelType::RvcV2), + WeightsType::SoVitsSvc => (InferenceCategory::VoiceConversion, InferenceModelType::SoVitsSvc), + WeightsType::Tacotron2 => (InferenceCategory::TextToSpeech, InferenceModelType::Tacotron2), + WeightsType::HifiganTacotron2 => continue, // Not supported for inference + WeightsType::StableDiffusion15 => continue, // TODO(bt,2023-12-18): Not yet set up with enums for inference + WeightsType::StableDiffusionXL => continue, // TODO(bt,2023-12-18): Not yet set up with enums for inference + WeightsType::LoRA => continue, // TODO(bt,2023-12-18): Not yet set up with enums for inference + WeightsType::VallE => continue, // TODO(bt,2023-12-18): ??? We have vall-e weights?? Not sure what this means yet. + }; + + let info = ModelInfoForInferenceJob { + job_inference_category: inference_category, + job_model_type: inference_model_type, + }; + + token_info_items.push((token_info.token.to_string(), info)); + } + + Ok(token_info_items) +} From b2555bc7569a0f5966f6983b159d4a66bdfefb2e Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Mon, 18 Dec 2023 21:37:31 -0500 Subject: [PATCH 071/124] populate "new token" --- .../dev-database-seed/src/seeding/voice_conversion.rs | 1 + .../insert_voice_conversion_model_from_download_job.rs | 9 +++++++-- .../models/list_voice_conversion_models.rs | 10 ---------- .../voice_conversion/rvc_v2/process_rvc_v2_model.rs | 1 + .../so_vits_svc/process_so_vits_svc_model.rs | 1 + .../voice_conversion/softvc/process_softvc_model.rs | 1 + 6 files changed, 11 insertions(+), 12 deletions(-) diff --git a/crates/cli/dev-database-seed/src/seeding/voice_conversion.rs b/crates/cli/dev-database-seed/src/seeding/voice_conversion.rs index 13ff2f72a3..fdc7fd6aca 100644 --- a/crates/cli/dev-database-seed/src/seeding/voice_conversion.rs +++ b/crates/cli/dev-database-seed/src/seeding/voice_conversion.rs @@ -44,6 +44,7 @@ async fn create_rvc_model( insert_voice_conversion_model_from_download_job(InsertVoiceConversionModelArgs { model_type: VoiceConversionModelType::RvcV2, + maybe_new_weights_token: None, title, original_download_url: "https://example.com", original_filename: "unknown.zip", diff --git a/crates/lib/mysql_queries/src/queries/voice_conversion/models/insert_voice_conversion_model_from_download_job.rs b/crates/lib/mysql_queries/src/queries/voice_conversion/models/insert_voice_conversion_model_from_download_job.rs index df199c754a..f5c5fe04c9 100644 --- a/crates/lib/mysql_queries/src/queries/voice_conversion/models/insert_voice_conversion_model_from_download_job.rs +++ b/crates/lib/mysql_queries/src/queries/voice_conversion/models/insert_voice_conversion_model_from_download_job.rs @@ -6,12 +6,15 @@ use sqlx::MySqlPool; use enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType; use enums::common::visibility::Visibility; use errors::AnyhowResult; +use tokens::tokens::model_weights::ModelWeightToken; use tokens::tokens::users::UserToken; use tokens::tokens::voice_conversion_models::VoiceConversionModelToken; pub struct InsertVoiceConversionModelArgs<'a, P: AsRef> { pub model_type: VoiceConversionModelType, + pub maybe_new_weights_token: Option<&'a ModelWeightToken>, + pub title: &'a str, pub original_download_url: &'a str, @@ -60,7 +63,8 @@ SET has_index_file = ?, private_bucket_hash = ?, private_bucket_object_name = ?, - file_size_bytes = ? + file_size_bytes = ?, + maybe_migration_new_model_weights_token = ? "#, &model_token, args.model_type.to_str(), @@ -72,7 +76,8 @@ SET args.has_index_file, args.private_bucket_hash, private_bucket_object_name, - args.file_size_bytes + args.file_size_bytes, + args.maybe_new_weights_token, ) .execute(args.mysql_pool) .await; diff --git a/crates/lib/mysql_queries/src/queries/voice_conversion/models/list_voice_conversion_models.rs b/crates/lib/mysql_queries/src/queries/voice_conversion/models/list_voice_conversion_models.rs index 8c3635245a..ace368acc0 100644 --- a/crates/lib/mysql_queries/src/queries/voice_conversion/models/list_voice_conversion_models.rs +++ b/crates/lib/mysql_queries/src/queries/voice_conversion/models/list_voice_conversion_models.rs @@ -29,11 +29,6 @@ pub struct VoiceConversionModelRecordForList { pub is_front_page_featured: bool, - // TODO(bt, 2023-04-18): Need columns for ratings - //pub user_ratings_positive_count: u32, - //pub user_ratings_negative_count: u32, - //pub user_ratings_total_count: u32, // NB: Does not include "neutral" ratings. - pub creator_set_visibility: Visibility, pub created_at: DateTime, @@ -183,11 +178,6 @@ struct RawVoiceConversionModelRecord { pub is_front_page_featured: i8, // bool - // TODO(bt, 2023-04-18): Need columns for ratings - //pub user_ratings_positive_count: u32, - //pub user_ratings_negative_count: u32, - //pub user_ratings_total_count: u32, // NB: Does not include "neutral" ratings. - pub creator_set_visibility: Visibility, pub created_at: DateTime, diff --git a/crates/service/job/download_job/src/job_types/voice_conversion/rvc_v2/process_rvc_v2_model.rs b/crates/service/job/download_job/src/job_types/voice_conversion/rvc_v2/process_rvc_v2_model.rs index f625647358..979298ea93 100644 --- a/crates/service/job/download_job/src/job_types/voice_conversion/rvc_v2/process_rvc_v2_model.rs +++ b/crates/service/job/download_job/src/job_types/voice_conversion/rvc_v2/process_rvc_v2_model.rs @@ -164,6 +164,7 @@ pub async fn process_rvc_v2_model<'a, 'b>( let (_id, voice_conversion_model_token) = insert_voice_conversion_model_from_download_job(InsertVoiceConversionModelArgs { model_type: VoiceConversionModelType::RvcV2, + maybe_new_weights_token: Some(&model_weights_token), title: &job.title, original_download_url: &job.download_url, original_filename: &download_filename, diff --git a/crates/service/job/download_job/src/job_types/voice_conversion/so_vits_svc/process_so_vits_svc_model.rs b/crates/service/job/download_job/src/job_types/voice_conversion/so_vits_svc/process_so_vits_svc_model.rs index 6502bdbeb6..cf6366dd62 100644 --- a/crates/service/job/download_job/src/job_types/voice_conversion/so_vits_svc/process_so_vits_svc_model.rs +++ b/crates/service/job/download_job/src/job_types/voice_conversion/so_vits_svc/process_so_vits_svc_model.rs @@ -109,6 +109,7 @@ pub async fn process_so_vits_svc_model<'a, 'b>( let (_id, voice_conversion_model_token) = insert_voice_conversion_model_from_download_job(InsertVoiceConversionModelArgs { model_type: VoiceConversionModelType::SoVitsSvc, + maybe_new_weights_token: Some(&model_weights_token), title: &job.title, original_download_url: &job.download_url, original_filename: &download_filename, diff --git a/crates/service/job/download_job/src/job_types/voice_conversion/softvc/process_softvc_model.rs b/crates/service/job/download_job/src/job_types/voice_conversion/softvc/process_softvc_model.rs index ea656c8dab..223a428145 100644 --- a/crates/service/job/download_job/src/job_types/voice_conversion/softvc/process_softvc_model.rs +++ b/crates/service/job/download_job/src/job_types/voice_conversion/softvc/process_softvc_model.rs @@ -100,6 +100,7 @@ pub async fn process_softvc_model<'a, 'b>( let (_id, model_token) = insert_voice_conversion_model_from_download_job(InsertVoiceConversionModelArgs { model_type: VoiceConversionModelType::SoftVc, + maybe_new_weights_token: None, title: &job.title, original_download_url: &job.download_url, original_filename: &download_filename, From d2faacc7964448dd9d3c51460a3240b4c0491426 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Mon, 18 Dec 2023 22:56:21 -0500 Subject: [PATCH 072/124] This might be it! model list is ported --- .../list_vc_models_for_migration.rs | 147 ++++++++++++++++++ .../lib/migration/src/voice_conversion/mod.rs | 1 + ...list_model_weights_for_voice_conversion.rs | 137 ++++++++++++++++ .../src/queries/model_weights/list/mod.rs | 1 + .../src/queries/model_weights/mod.rs | 3 +- .../models/list_voice_conversion_models.rs | 2 +- .../common_responses/user_details_lite.rs | 6 +- .../models/list_voice_conversion_models.rs | 79 ++++------ .../service/web/storyteller_web/src/main.rs | 1 + .../web/storyteller_web/src/server_state.rs | 7 + 10 files changed, 331 insertions(+), 53 deletions(-) create mode 100644 crates/lib/migration/src/voice_conversion/list_vc_models_for_migration.rs create mode 100644 crates/lib/mysql_queries/src/queries/model_weights/list/list_model_weights_for_voice_conversion.rs create mode 100644 crates/lib/mysql_queries/src/queries/model_weights/list/mod.rs diff --git a/crates/lib/migration/src/voice_conversion/list_vc_models_for_migration.rs b/crates/lib/migration/src/voice_conversion/list_vc_models_for_migration.rs new file mode 100644 index 0000000000..9028b510f8 --- /dev/null +++ b/crates/lib/migration/src/voice_conversion/list_vc_models_for_migration.rs @@ -0,0 +1,147 @@ +use chrono::{DateTime, Utc}; +use sqlx::MySql; +use sqlx::pool::PoolConnection; +use enums::by_table::model_weights::weights_types::WeightsType; +use enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType; + +use enums::common::visibility::Visibility; +use errors::AnyhowResult; +use mysql_queries::queries::model_weights::list::list_model_weights_for_voice_conversion::{list_model_weights_for_voice_conversion, ModelWeightForVoiceConversion}; +use mysql_queries::queries::voice_conversion::models::list_voice_conversion_models::{list_voice_conversion_models_with_connection, VoiceConversionModelRecordForList}; +use tokens::tokens::users::UserToken; + +/// List VC models +/// This is for the voice conversion model list page. +/// Since we're listing, we have to use a flag to determine which query to perform. +pub async fn list_vc_models_for_migration( + mysql_connection: &mut PoolConnection, + use_weights_table: bool, +) -> AnyhowResult> { + // NB: This is temporary migration code as we switch from the `voice_conversion_models` table to the `model_weights` table. + if use_weights_table { + let models = list_model_weights_for_voice_conversion( + mysql_connection).await?; + + Ok(models.into_iter() + .map(|model| VcModelForList::ModelWeight(model)) + .collect()) + + } else { + let models = list_voice_conversion_models_with_connection( + mysql_connection, None).await?; + + Ok(models.into_iter() + .map(|model| VcModelForList::LegacyVoiceConversion(model)) + .collect()) + } +} + +/// Union over the legacy table and the new table to support an easier migration. +/// This enum can hold a record of either type and present a unified accessor interface. +#[derive(Clone)] +pub enum VcModelForList { + /// Old type from the `voice_conversion_models` table, on the way out + LegacyVoiceConversion(VoiceConversionModelRecordForList), + /// New type, replacing the `voice_conversion_models` table. + ModelWeight(ModelWeightForVoiceConversion), +} + +impl VcModelForList { + pub fn token(&self) -> &str { + match self { + VcModelForList::LegacyVoiceConversion(ref model) => model.token.as_str(), + VcModelForList::ModelWeight(ref model) => model.token.as_str(), + } + } + + pub fn legacy_voice_conversion_model_type(&self) -> Option { + match self { + VcModelForList::LegacyVoiceConversion(ref model) => Some(model.model_type), + VcModelForList::ModelWeight(ref model) => match model.weight_type { + WeightsType::SoVitsSvc => Some(VoiceConversionModelType::SoVitsSvc), + WeightsType::RvcV2 => Some(VoiceConversionModelType::RvcV2), + // NB: The following weights are not voice conversion models. + WeightsType::HifiganTacotron2 => None, + WeightsType::StableDiffusion15 => None, + WeightsType::StableDiffusionXL => None, + WeightsType::Tacotron2 => None, + WeightsType::LoRA => None, + WeightsType::VallE => None, + }, + } + } + + pub fn is_voice_conversion_model(&self) -> bool { + self.legacy_voice_conversion_model_type().is_some() + } + + pub fn title(&self) -> &str { + match self { + VcModelForList::LegacyVoiceConversion(ref model) => &model.title, + VcModelForList::ModelWeight(ref model) => &model.title, + } + } + + pub fn ietf_language_tag(&self) -> &str { + match self { + VcModelForList::LegacyVoiceConversion(ref model) => &model.ietf_language_tag, + VcModelForList::ModelWeight(ref model) => &model.ietf_language_tag, + } + } + + pub fn ietf_primary_language_subtag(&self) -> &str { + match self { + VcModelForList::LegacyVoiceConversion(ref model) => &model.ietf_primary_language_subtag, + VcModelForList::ModelWeight(ref model) => &model.ietf_primary_language_subtag, + } + } + + pub fn creator_user_token(&self) -> &UserToken { + match self { + VcModelForList::LegacyVoiceConversion(ref model) => &model.creator_user_token, + VcModelForList::ModelWeight(ref model) => &model.creator_user_token, + } + } + + pub fn creator_username(&self) -> &str { + match self { + VcModelForList::LegacyVoiceConversion(ref model) => &model.creator_username, + VcModelForList::ModelWeight(ref model) => &model.creator_username, + } + } + + pub fn creator_display_name(&self) -> &str { + match self { + VcModelForList::LegacyVoiceConversion(ref model) => &model.creator_display_name, + VcModelForList::ModelWeight(ref model) => &model.creator_display_name, + } + } + + pub fn creator_gravatar_hash(&self) -> &str { + match self { + VcModelForList::LegacyVoiceConversion(ref model) => &model.creator_gravatar_hash, + VcModelForList::ModelWeight(ref model) => &model.creator_gravatar_hash, + } + } + + pub fn creator_set_visibility(&self) -> Visibility{ + match self { + VcModelForList::LegacyVoiceConversion(ref model) => model.creator_set_visibility, + VcModelForList::ModelWeight(ref model) => model.creator_set_visibility, + } + } + + pub fn created_at(&self) -> &DateTime { + match self { + VcModelForList::LegacyVoiceConversion(ref model) => &model.created_at, + VcModelForList::ModelWeight(ref model) => &model.created_at, + } + } + + pub fn updated_at(&self) -> &DateTime { + match self { + VcModelForList::LegacyVoiceConversion(ref model) => &model.updated_at, + VcModelForList::ModelWeight(ref model) => &model.updated_at, + } + } +} diff --git a/crates/lib/migration/src/voice_conversion/mod.rs b/crates/lib/migration/src/voice_conversion/mod.rs index 1ddf3677ee..139f134db9 100644 --- a/crates/lib/migration/src/voice_conversion/mod.rs +++ b/crates/lib/migration/src/voice_conversion/mod.rs @@ -1,2 +1,3 @@ +pub mod list_vc_models_for_migration; pub mod query_vc_model_for_migration; pub mod query_vc_model_info_lite_for_migration; diff --git a/crates/lib/mysql_queries/src/queries/model_weights/list/list_model_weights_for_voice_conversion.rs b/crates/lib/mysql_queries/src/queries/model_weights/list/list_model_weights_for_voice_conversion.rs new file mode 100644 index 0000000000..a902934e4f --- /dev/null +++ b/crates/lib/mysql_queries/src/queries/model_weights/list/list_model_weights_for_voice_conversion.rs @@ -0,0 +1,137 @@ +use anyhow::anyhow; +use chrono::{DateTime, Utc}; +use log::warn; +use sqlx::{MySql, MySqlPool}; +use sqlx::pool::PoolConnection; +use enums::by_table::model_weights::weights_types::WeightsType; + +use enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType; +use enums::common::visibility::Visibility; +use errors::AnyhowResult; +use tokens::tokens::model_weights::ModelWeightToken; +use tokens::tokens::users::UserToken; +use tokens::tokens::voice_conversion_models::VoiceConversionModelToken; + +use crate::helpers::boolean_converters::i8_to_bool; + +#[derive(Serialize, Clone)] +pub struct ModelWeightForVoiceConversion { + pub token: ModelWeightToken, + pub weight_type: WeightsType, + + pub title: String, + + pub ietf_language_tag: String, + pub ietf_primary_language_subtag: String, + + pub creator_user_token: UserToken, + pub creator_username: String, + pub creator_display_name: String, + pub creator_gravatar_hash: String, + + // TODO(bt,2023-12-18): This should probably live in the extension table. + //pub is_front_page_featured: bool, + + pub creator_set_visibility: Visibility, + + pub created_at: DateTime, + pub updated_at: DateTime, +} + +// TODO(bt,2023-12-18): This is written to support the migration to the `model_weights` +// table from the `voice_conversion_models` table. We should write a more cross-cutting +// query to treat this not as a special cased thing. All weights should be listable. + +/// This is to support the voice conversion list page. +/// Later this will be migrated or replaced with a more generic query. +pub async fn list_model_weights_for_voice_conversion( + mysql_connection: &mut PoolConnection, +) -> AnyhowResult> { + + let models = + list_voice_conversion_models_for_all_creators(mysql_connection).await?; + + Ok(models.into_iter() + .map(|model| { + ModelWeightForVoiceConversion { + token: model.token, + weight_type: model.weight_type, + creator_user_token: model.creator_user_token, + creator_username: model.creator_username, + creator_display_name: model.creator_display_name, + creator_gravatar_hash: model.creator_gravatar_hash, + title: model.title, + ietf_language_tag: model.ietf_language_tag.unwrap_or("en".to_string()), + ietf_primary_language_subtag: model.ietf_primary_language_subtag.unwrap_or("en".to_string()), + creator_set_visibility: model.creator_set_visibility, + created_at: model.created_at, + updated_at: model.updated_at, + } + }) + .collect::>()) +} + +async fn list_voice_conversion_models_for_all_creators( + mysql_connection: &mut PoolConnection, +) -> AnyhowResult> { + // NB: Scoped to only rvc_v2 and so_vits_svc weights + let maybe_results = sqlx::query_as!( + RawModelWeightForVoiceConversion, + r#" +SELECT + w.token as `token: tokens::tokens::model_weights::ModelWeightToken`, + w.weights_type as `weight_type: enums::by_table::model_weights::weights_types::WeightsType`, + w.creator_user_token as `creator_user_token: tokens::tokens::users::UserToken`, + users.username as creator_username, + users.display_name as creator_display_name, + users.email_gravatar_hash as creator_gravatar_hash, + w.title, + w_extension.ietf_language_tag, + w_extension.ietf_primary_language_subtag, + w.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`, + w.created_at, + w.updated_at +FROM model_weights as w +LEFT OUTER JOIN model_weights_extension_voice_conversion_details as w_extension + ON w_extension.model_weights_token = w.token +JOIN users + ON users.token = w.creator_user_token +WHERE + w.weights_type IN ("rvc_v2", "so_vits_svc") + AND w.user_deleted_at IS NULL + AND w.mod_deleted_at IS NULL + "# + ) + .fetch_all(&mut **mysql_connection) + .await; + + match maybe_results { + Ok(results) => Ok(results), + Err(err) => match err { + sqlx::Error::RowNotFound => Ok(Vec::new()), + _ => { + Err(anyhow!("error querying : {:?}", err)) + } + } + } +} + +struct RawModelWeightForVoiceConversion { + pub token: ModelWeightToken, + pub weight_type: WeightsType, + + pub title: String, + + pub ietf_language_tag: Option, + pub ietf_primary_language_subtag: Option, + + pub creator_user_token: UserToken, + pub creator_username: String, + pub creator_display_name: String, + pub creator_gravatar_hash: String, + + pub creator_set_visibility: Visibility, + + pub created_at: DateTime, + pub updated_at: DateTime, +} diff --git a/crates/lib/mysql_queries/src/queries/model_weights/list/mod.rs b/crates/lib/mysql_queries/src/queries/model_weights/list/mod.rs new file mode 100644 index 0000000000..597399a9c0 --- /dev/null +++ b/crates/lib/mysql_queries/src/queries/model_weights/list/mod.rs @@ -0,0 +1 @@ +pub mod list_model_weights_for_voice_conversion; \ No newline at end of file diff --git a/crates/lib/mysql_queries/src/queries/model_weights/mod.rs b/crates/lib/mysql_queries/src/queries/model_weights/mod.rs index 62ad3e22fa..c42a3f6d9d 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/mod.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/mod.rs @@ -3,10 +3,11 @@ pub mod create_weight; pub mod delete_weights; pub mod get_weight; pub mod inference; +pub mod list; pub mod list_weights_by_tokens; pub mod list_weights_by_user; pub mod list_weights_query_builder; pub mod migration; +pub mod model_weight_info_lite; pub mod tests; pub mod update_weight; -pub mod model_weight_info_lite; diff --git a/crates/lib/mysql_queries/src/queries/voice_conversion/models/list_voice_conversion_models.rs b/crates/lib/mysql_queries/src/queries/voice_conversion/models/list_voice_conversion_models.rs index ace368acc0..5476272290 100644 --- a/crates/lib/mysql_queries/src/queries/voice_conversion/models/list_voice_conversion_models.rs +++ b/crates/lib/mysql_queries/src/queries/voice_conversion/models/list_voice_conversion_models.rs @@ -12,7 +12,7 @@ use tokens::tokens::voice_conversion_models::VoiceConversionModelToken; use crate::helpers::boolean_converters::i8_to_bool; -#[derive(Serialize)] +#[derive(Serialize, Clone)] pub struct VoiceConversionModelRecordForList { pub token: VoiceConversionModelToken, pub model_type: VoiceConversionModelType, diff --git a/crates/service/web/storyteller_web/src/http_server/common_responses/user_details_lite.rs b/crates/service/web/storyteller_web/src/http_server/common_responses/user_details_lite.rs index 582296e109..5587dbe372 100644 --- a/crates/service/web/storyteller_web/src/http_server/common_responses/user_details_lite.rs +++ b/crates/service/web/storyteller_web/src/http_server/common_responses/user_details_lite.rs @@ -1,10 +1,12 @@ +use utoipa::ToSchema; + use tokens::tokens::users::UserToken; use crate::user_avatars::default_avatar_color_from_username::default_avatar_color_from_username; use crate::user_avatars::default_avatar_from_username::default_avatar_from_username; -use utoipa::ToSchema; + /// Everything we need to refer to a user on the public web interface. -#[derive(Clone, Serialize,ToSchema)] +#[derive(Clone, Serialize, ToSchema)] pub struct UserDetailsLight { /// The token for the user pub user_token: UserToken, diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_conversion/models/list_voice_conversion_models.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_conversion/models/list_voice_conversion_models.rs index 3a12442b40..608d7da4ac 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/voice_conversion/models/list_voice_conversion_models.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/voice_conversion/models/list_voice_conversion_models.rs @@ -18,21 +18,23 @@ use sqlx::pool::PoolConnection; use enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType; use enums::common::visibility::Visibility; use errors::AnyhowResult; +use migration::voice_conversion::list_vc_models_for_migration::list_vc_models_for_migration; use mysql_queries::queries::users::user_sessions::get_user_session_by_token::SessionUserRecord; -use mysql_queries::queries::voice_conversion::models::list_voice_conversion_models::list_voice_conversion_models_with_connection; -use tokens::tokens::users::UserToken; -use tokens::tokens::voice_conversion_models::VoiceConversionModelToken; +use crate::http_server::common_responses::user_details_lite::UserDetailsLight; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; use crate::server_state::ServerState; #[derive(Serialize, Clone)] pub struct VoiceConversionModel { - pub token: VoiceConversionModelToken, + /// NB: token can be a `model_weights` token or a `voice_conversion_models` token. + pub token: String, + pub model_type: VoiceConversionModelType, + pub title: String, - pub creator: CreatorDetails, + pub creator: UserDetailsLight, pub creator_set_visibility: Visibility, pub ietf_language_tag: String, @@ -51,14 +53,6 @@ pub struct VoiceConversionModel { pub updated_at: DateTime, } -#[derive(Serialize, Clone)] -pub struct CreatorDetails { - pub user_token: UserToken, - pub username: String, - pub display_name: String, - pub gravatar_hash: String, -} - // TODO: Add user ratings. //#[derive(Serialize, Clone)] //pub struct UserRatingsStats { @@ -140,7 +134,7 @@ pub async fn list_voice_conversion_models_handler( })?; // TODO: Fail open in case the DB is down. Pull from expired cache if query fails. - let models = get_all_models(&mut mysql_connection) + let models = get_all_models(&mut mysql_connection, server_state.flags.switch_voice_conversion_to_model_weights) .await .map_err(|e| { error!("Error querying database: {:?}", e); @@ -219,47 +213,34 @@ pub fn render_response_payload(response: ListVoiceConversionModelsSuccessRespons Ok(body) } -async fn get_all_models(mysql_connection: &mut PoolConnection) -> AnyhowResult> { - let mut models = list_voice_conversion_models_with_connection( - mysql_connection, - None, - ).await?; +async fn get_all_models(mysql_connection: &mut PoolConnection, use_weights_table: bool) -> AnyhowResult> { + let mut models = list_vc_models_for_migration(mysql_connection, use_weights_table).await?; - //let model_categories_map - // = fetch_and_build_voice_conversion_model_category_map_with_connection(mysql_connection).await?; - - // Make the list nice for human readers. + // NB: Make the list nice for human readers. models.sort_by(|a, b| - natural_lexical_cmp(&a.title, &b.title)); + natural_lexical_cmp(&a.title(), &b.title())); let models_for_response = models.into_iter() + .filter(|model| model.is_voice_conversion_model()) .map(|model| { + // TODO(bt,2023-12-18): All of these clones are lame, but this is just to support the migration. VoiceConversionModel { - token: model.token, - model_type: model.model_type, - title: model.title, - creator: CreatorDetails { - user_token: model.creator_user_token, - username: model.creator_username, - display_name: model.creator_display_name, - gravatar_hash: model.creator_gravatar_hash, - }, - creator_set_visibility: model.creator_set_visibility, - ietf_language_tag: model.ietf_language_tag, - ietf_primary_language_subtag: model.ietf_primary_language_subtag, - is_front_page_featured: model.is_front_page_featured, - // TODO: Add user ratings - //user_ratings: UserRatingsStats { - // positive_count: model.user_ratings_positive_count, - // negative_count: model.user_ratings_negative_count, - // total_count: model.user_ratings_total_count, - //}, - // TODO: Add categories - //category_tokens: model_categories_map.model_to_category_tokens.get(&model_token) - // .map(|hash| hash.clone()) - // .unwrap_or(HashSet::new()), - created_at: model.created_at, - updated_at: model.updated_at, + token: model.token().to_string(), + model_type: model.legacy_voice_conversion_model_type() + .unwrap_or(VoiceConversionModelType::SoVitsSvc), + title: model.title().to_string(), + is_front_page_featured: false, // TODO(bt,2023-12-18): None of the models are "featured" yet. + creator: UserDetailsLight::from_db_fields( + model.creator_user_token(), + model.creator_username(), + model.creator_display_name(), + model.creator_gravatar_hash(), + ), + creator_set_visibility: model.creator_set_visibility(), + ietf_language_tag: model.ietf_language_tag().to_string(), + ietf_primary_language_subtag: model.ietf_primary_language_subtag().to_string(), + created_at: model.created_at().clone(), + updated_at: model.updated_at().clone(), } }) .collect::>(); diff --git a/crates/service/web/storyteller_web/src/main.rs b/crates/service/web/storyteller_web/src/main.rs index 8b815cd6f3..ea439a16bf 100644 --- a/crates/service/web/storyteller_web/src/main.rs +++ b/crates/service/web/storyteller_web/src/main.rs @@ -358,6 +358,7 @@ async fn main() -> AnyhowResult<()> { // Temporary flags enable_enqueue_generic_tts_job: easyenv::get_env_bool_or_default("FF_ENABLE_ENQUEUE_GENERIC_TTS_JOB", false), + switch_voice_conversion_to_model_weights: easyenv::get_env_bool_or_default("FF_SWITCH_VOICE_CONVERSION_TO_MODEL_WEIGHTS", false), }; let third_party_url_redirector = ThirdPartyUrlRedirector::new(server_environment); diff --git a/crates/service/web/storyteller_web/src/server_state.rs b/crates/service/web/storyteller_web/src/server_state.rs index c7ba601993..38264e89c2 100644 --- a/crates/service/web/storyteller_web/src/server_state.rs +++ b/crates/service/web/storyteller_web/src/server_state.rs @@ -254,8 +254,15 @@ pub struct StaticFeatureFlags { /// This should be a number over 100. pub troll_ban_user_percent: u8, + // TODO(2023-03-20): Remove temporary flag when done. + // NB(bt,2023-12-18): This is rolled out (=="TRUE") /// TEMPORARY: Control enqueuing TTS jobs to the generic job worker. pub enable_enqueue_generic_tts_job: bool, + + // TODO(2023-12-18): Remove temporary flag when done. + /// TEMPORARY: Move voice control model listing over to `model_weights` from `voice_conversion_models` + /// This will control all downstream enqueuing, jobs, etc. + pub switch_voice_conversion_to_model_weights: bool, } /// Instead of top level service denial, these are bans against entities that instead return From 2b186720c17d87b567c67f6ff866e87e7af7c129 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Tue, 19 Dec 2023 01:32:11 -0500 Subject: [PATCH 073/124] analytic query --- .../generic_inference_jobs.sql | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/_sql/analytics/generic_inference/generic_inference_jobs.sql b/_sql/analytics/generic_inference/generic_inference_jobs.sql index aa6ace1752..6da38379a6 100644 --- a/_sql/analytics/generic_inference/generic_inference_jobs.sql +++ b/_sql/analytics/generic_inference/generic_inference_jobs.sql @@ -23,6 +23,27 @@ and success_execution_millis IS NOT NULL order by id desc limit 50; +-- See how many are using a deleted model +select + creator_ip_address, + count(*) +from generic_inference_jobs +where maybe_model_token = 'vcm_4x8a30h1r26z' +and created_at > NOW() - INTERVAL 24 HOUR +group by creator_ip_address + +-- See which deleted models are in use +select + vm.token, + vm.title, + count(*) +from generic_inference_jobs as j +join voice_conversion_models as vm +on j.maybe_model_token = vm.token +where vm.mod_deleted_at IS NOT NULL + and j.created_at > NOW() - INTERVAL 24 HOUR +group by vm.token, vm.title + -- See who is uploading SadTalker jobs select maybe_creator_user_token, From 4edea1d68f0bafa82d3364d326f840aea82f78d7 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Tue, 19 Dec 2023 01:40:40 -0500 Subject: [PATCH 074/124] codegen db + fix compile error --- ...e4b9a27f44c4bdacb8548d06a9e1dfb3db03.json} | 6 +- ...27058075414496dc5858d57a9f06d7c076bab.json | 135 +++++++ ...f4aff39656262147e97f3e8d8eb59497fcbd5.json | 12 + ...63b7e6b243c34a784e3f66f06aa102af3f1f9.json | 12 + ...df5081ac69fdbb856fffcbd68187fd99c4642.json | 6 +- ...a3d69b1e34361294f7e90733a497cb8643908.json | 146 ++++++++ ...c71106bbcbbb205f54c14e3657279e83dabb6.json | 8 +- ...3a2c40f21ec732693b92ad4bda69ae2b8d5bb.json | 36 ++ ...8f56b6bdee35bac63c9eacbe21eb032a6a831.json | 6 +- ...b4d2a8b3801fd27999be19cb47f5f86ea279c.json | 344 ++++++++++++++++++ ...746f6f33a9e1c25f21f66aeeb0784df768c8e.json | 8 +- ...6c5975f9438c88421f19a1788531f335e75c2.json | 36 ++ ...30d899c8704a55999866d4cd2bce561a40065.json | 12 + .../rerender_a_video/download_model_file.rs | 4 +- 14 files changed, 753 insertions(+), 18 deletions(-) rename .sqlx/{query-1e85e546684feffc151a26b0495b9ab8aa4ee5f1627464a9872e9c357ba1dc7a.json => query-06734395f0a844e59d26c7d1cbc3e4b9a27f44c4bdacb8548d06a9e1dfb3db03.json} (75%) create mode 100644 .sqlx/query-0d4c43d9055cea3ce35c71ab8ef27058075414496dc5858d57a9f06d7c076bab.json create mode 100644 .sqlx/query-2a8ac5f5cf9d955f154ef9369eff4aff39656262147e97f3e8d8eb59497fcbd5.json create mode 100644 .sqlx/query-34aaedaebab0ea772714f31f42563b7e6b243c34a784e3f66f06aa102af3f1f9.json create mode 100644 .sqlx/query-57a63d507ccd60824e0cf346a6aa3d69b1e34361294f7e90733a497cb8643908.json create mode 100644 .sqlx/query-98d53b1732bf0b0642ac6ebae3a3a2c40f21ec732693b92ad4bda69ae2b8d5bb.json create mode 100644 .sqlx/query-d1da969247415305e6bff625150b4d2a8b3801fd27999be19cb47f5f86ea279c.json create mode 100644 .sqlx/query-f80fb6c91b897bc4a5c24cfd1e16c5975f9438c88421f19a1788531f335e75c2.json create mode 100644 .sqlx/query-fbcaa705fac9d2262a8b3ac337e30d899c8704a55999866d4cd2bce561a40065.json diff --git a/.sqlx/query-1e85e546684feffc151a26b0495b9ab8aa4ee5f1627464a9872e9c357ba1dc7a.json b/.sqlx/query-06734395f0a844e59d26c7d1cbc3e4b9a27f44c4bdacb8548d06a9e1dfb3db03.json similarity index 75% rename from .sqlx/query-1e85e546684feffc151a26b0495b9ab8aa4ee5f1627464a9872e9c357ba1dc7a.json rename to .sqlx/query-06734395f0a844e59d26c7d1cbc3e4b9a27f44c4bdacb8548d06a9e1dfb3db03.json index d22bde5dda..b9c9d34d77 100644 --- a/.sqlx/query-1e85e546684feffc151a26b0495b9ab8aa4ee5f1627464a9872e9c357ba1dc7a.json +++ b/.sqlx/query-06734395f0a844e59d26c7d1cbc3e4b9a27f44c4bdacb8548d06a9e1dfb3db03.json @@ -1,12 +1,12 @@ { "db_name": "MySQL", - "query": "\nINSERT INTO voice_conversion_models\nSET\n token = ?,\n model_type = ?,\n title = ?,\n description_markdown = '',\n description_rendered_html = '',\n creator_user_token = ?,\n ip_address_creation = ?,\n ip_address_last_update = ?,\n original_download_url = ?,\n has_index_file = ?,\n private_bucket_hash = ?,\n private_bucket_object_name = ?,\n file_size_bytes = ?\n ", + "query": "\nINSERT INTO voice_conversion_models\nSET\n token = ?,\n model_type = ?,\n title = ?,\n description_markdown = '',\n description_rendered_html = '',\n creator_user_token = ?,\n ip_address_creation = ?,\n ip_address_last_update = ?,\n original_download_url = ?,\n has_index_file = ?,\n private_bucket_hash = ?,\n private_bucket_object_name = ?,\n file_size_bytes = ?,\n maybe_migration_new_model_weights_token = ?\n ", "describe": { "columns": [], "parameters": { - "Right": 11 + "Right": 12 }, "nullable": [] }, - "hash": "1e85e546684feffc151a26b0495b9ab8aa4ee5f1627464a9872e9c357ba1dc7a" + "hash": "06734395f0a844e59d26c7d1cbc3e4b9a27f44c4bdacb8548d06a9e1dfb3db03" } diff --git a/.sqlx/query-0d4c43d9055cea3ce35c71ab8ef27058075414496dc5858d57a9f06d7c076bab.json b/.sqlx/query-0d4c43d9055cea3ce35c71ab8ef27058075414496dc5858d57a9f06d7c076bab.json new file mode 100644 index 0000000000..e6e8bbeced --- /dev/null +++ b/.sqlx/query-0d4c43d9055cea3ce35c71ab8ef27058075414496dc5858d57a9f06d7c076bab.json @@ -0,0 +1,135 @@ +{ + "db_name": "MySQL", + "query": "\nSELECT\n w.token as `token: tokens::tokens::model_weights::ModelWeightToken`,\n w.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n\n w.title,\n vc.has_index_file,\n\n w.private_bucket_hash,\n w.maybe_private_bucket_prefix,\n w.maybe_private_bucket_extension,\n\n w.created_at,\n w.updated_at,\n w.user_deleted_at,\n w.mod_deleted_at\n\nFROM model_weights as w\nJOIN model_weights_extension_voice_conversion_details as vc\nON vc.model_weights_token = w.token\n\nWHERE w.token = ?\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "token: tokens::tokens::model_weights::ModelWeightToken", + "type_info": { + "type": "VarString", + "flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 128 + } + }, + { + "ordinal": 1, + "name": "weights_type: enums::by_table::model_weights::weights_types::WeightsType", + "type_info": { + "type": "VarString", + "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 128 + } + }, + { + "ordinal": 2, + "name": "title", + "type_info": { + "type": "VarString", + "flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 1020 + } + }, + { + "ordinal": 3, + "name": "has_index_file", + "type_info": { + "type": "Tiny", + "flags": "NOT_NULL", + "char_set": 63, + "max_size": 1 + } + }, + { + "ordinal": 4, + "name": "private_bucket_hash", + "type_info": { + "type": "VarString", + "flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 128 + } + }, + { + "ordinal": 5, + "name": "maybe_private_bucket_prefix", + "type_info": { + "type": "VarString", + "flags": "BINARY", + "char_set": 224, + "max_size": 64 + } + }, + { + "ordinal": 6, + "name": "maybe_private_bucket_extension", + "type_info": { + "type": "VarString", + "flags": "BINARY", + "char_set": 224, + "max_size": 64 + } + }, + { + "ordinal": 7, + "name": "created_at", + "type_info": { + "type": "Timestamp", + "flags": "NOT_NULL | BINARY | TIMESTAMP", + "char_set": 63, + "max_size": 19 + } + }, + { + "ordinal": 8, + "name": "updated_at", + "type_info": { + "type": "Timestamp", + "flags": "NOT_NULL | BINARY | TIMESTAMP | ON_UPDATE_NOW", + "char_set": 63, + "max_size": 19 + } + }, + { + "ordinal": 9, + "name": "user_deleted_at", + "type_info": { + "type": "Timestamp", + "flags": "BINARY", + "char_set": 63, + "max_size": 19 + } + }, + { + "ordinal": 10, + "name": "mod_deleted_at", + "type_info": { + "type": "Timestamp", + "flags": "BINARY", + "char_set": 63, + "max_size": 19 + } + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + false, + false, + false, + false, + false, + true, + true, + false, + false, + true, + true + ] + }, + "hash": "0d4c43d9055cea3ce35c71ab8ef27058075414496dc5858d57a9f06d7c076bab" +} diff --git a/.sqlx/query-2a8ac5f5cf9d955f154ef9369eff4aff39656262147e97f3e8d8eb59497fcbd5.json b/.sqlx/query-2a8ac5f5cf9d955f154ef9369eff4aff39656262147e97f3e8d8eb59497fcbd5.json new file mode 100644 index 0000000000..0f64b66b1e --- /dev/null +++ b/.sqlx/query-2a8ac5f5cf9d955f154ef9369eff4aff39656262147e97f3e8d8eb59497fcbd5.json @@ -0,0 +1,12 @@ +{ + "db_name": "MySQL", + "query": "\nINSERT INTO model_weights\nSET\n token = ?,\n weights_type = ?,\n weights_category = ?,\n title = ?,\n\n maybe_thumbnail_token = NULL,\n maybe_avatar_media_file_token = NULL,\n maybe_cover_media_file_token = NULL,\n description_markdown = NULL,\n description_rendered_html = NULL,\n\n maybe_last_update_user_token = NULL,\n original_download_url = ?,\n original_filename = ?,\n file_size_bytes = ?,\n file_checksum_sha2 = \"TODO\",\n\n creator_user_token = ?,\n creator_ip_address = ?,\n creator_set_visibility = ?,\n\n private_bucket_hash = ?,\n maybe_private_bucket_prefix = ?,\n maybe_private_bucket_extension = ?,\n\n cached_user_ratings_total_count = 0,\n cached_user_ratings_positive_count = 0,\n cached_user_ratings_negative_count = 0,\n maybe_cached_user_ratings_ratio = 0.0,\n cached_user_ratings_last_updated_at = NOW(),\n\n maybe_migration_old_model_token = ?\n ", + "describe": { + "columns": [], + "parameters": { + "Right": 14 + }, + "nullable": [] + }, + "hash": "2a8ac5f5cf9d955f154ef9369eff4aff39656262147e97f3e8d8eb59497fcbd5" +} diff --git a/.sqlx/query-34aaedaebab0ea772714f31f42563b7e6b243c34a784e3f66f06aa102af3f1f9.json b/.sqlx/query-34aaedaebab0ea772714f31f42563b7e6b243c34a784e3f66f06aa102af3f1f9.json new file mode 100644 index 0000000000..1b2f1ab2cd --- /dev/null +++ b/.sqlx/query-34aaedaebab0ea772714f31f42563b7e6b243c34a784e3f66f06aa102af3f1f9.json @@ -0,0 +1,12 @@ +{ + "db_name": "MySQL", + "query": "\nINSERT INTO model_weights_extension_voice_conversion_details\nSET\n model_weights_token = ?,\n has_index_file = ?\n ", + "describe": { + "columns": [], + "parameters": { + "Right": 2 + }, + "nullable": [] + }, + "hash": "34aaedaebab0ea772714f31f42563b7e6b243c34a784e3f66f06aa102af3f1f9" +} diff --git a/.sqlx/query-3d586592422727dcc928574966bdf5081ac69fdbb856fffcbd68187fd99c4642.json b/.sqlx/query-3d586592422727dcc928574966bdf5081ac69fdbb856fffcbd68187fd99c4642.json index d26bd32bec..98ea6ac401 100644 --- a/.sqlx/query-3d586592422727dcc928574966bdf5081ac69fdbb856fffcbd68187fd99c4642.json +++ b/.sqlx/query-3d586592422727dcc928574966bdf5081ac69fdbb856fffcbd68187fd99c4642.json @@ -28,7 +28,7 @@ "name": "weights_type: enums::by_table::model_weights::weights_types::WeightsType", "type_info": { "type": "VarString", - "flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE", + "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE", "char_set": 224, "max_size": 128 } @@ -38,7 +38,7 @@ "name": "weights_category: enums::by_table::model_weights::weights_category::WeightsCategory", "type_info": { "type": "VarString", - "flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE", + "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE", "char_set": 224, "max_size": 128 } @@ -128,7 +128,7 @@ "name": "creator_set_visibility: enums::common::visibility::Visibility", "type_info": { "type": "String", - "flags": "NOT_NULL | BINARY | ENUM", + "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | ENUM", "char_set": 224, "max_size": 28 } diff --git a/.sqlx/query-57a63d507ccd60824e0cf346a6aa3d69b1e34361294f7e90733a497cb8643908.json b/.sqlx/query-57a63d507ccd60824e0cf346a6aa3d69b1e34361294f7e90733a497cb8643908.json new file mode 100644 index 0000000000..7ae98fcf69 --- /dev/null +++ b/.sqlx/query-57a63d507ccd60824e0cf346a6aa3d69b1e34361294f7e90733a497cb8643908.json @@ -0,0 +1,146 @@ +{ + "db_name": "MySQL", + "query": "\nSELECT\n w.token as `token: tokens::tokens::model_weights::ModelWeightToken`,\n w.weights_type as `weight_type: enums::by_table::model_weights::weights_types::WeightsType`,\n w.creator_user_token as `creator_user_token: tokens::tokens::users::UserToken`,\n users.username as creator_username,\n users.display_name as creator_display_name,\n users.email_gravatar_hash as creator_gravatar_hash,\n w.title,\n w_extension.ietf_language_tag,\n w_extension.ietf_primary_language_subtag,\n w.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n w.created_at,\n w.updated_at\nFROM model_weights as w\nLEFT OUTER JOIN model_weights_extension_voice_conversion_details as w_extension\n ON w_extension.model_weights_token = w.token\nJOIN users\n ON users.token = w.creator_user_token\nWHERE\n w.weights_type IN (\"rvc_v2\", \"so_vits_svc\")\n AND w.user_deleted_at IS NULL\n AND w.mod_deleted_at IS NULL\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "token: tokens::tokens::model_weights::ModelWeightToken", + "type_info": { + "type": "VarString", + "flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 128 + } + }, + { + "ordinal": 1, + "name": "weight_type: enums::by_table::model_weights::weights_types::WeightsType", + "type_info": { + "type": "VarString", + "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 128 + } + }, + { + "ordinal": 2, + "name": "creator_user_token: tokens::tokens::users::UserToken", + "type_info": { + "type": "VarString", + "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 128 + } + }, + { + "ordinal": 3, + "name": "creator_username", + "type_info": { + "type": "VarString", + "flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 80 + } + }, + { + "ordinal": 4, + "name": "creator_display_name", + "type_info": { + "type": "VarString", + "flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 80 + } + }, + { + "ordinal": 5, + "name": "creator_gravatar_hash", + "type_info": { + "type": "String", + "flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 128 + } + }, + { + "ordinal": 6, + "name": "title", + "type_info": { + "type": "VarString", + "flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 1020 + } + }, + { + "ordinal": 7, + "name": "ietf_language_tag", + "type_info": { + "type": "VarString", + "flags": "BINARY", + "char_set": 224, + "max_size": 256 + } + }, + { + "ordinal": 8, + "name": "ietf_primary_language_subtag", + "type_info": { + "type": "VarString", + "flags": "BINARY", + "char_set": 224, + "max_size": 48 + } + }, + { + "ordinal": 9, + "name": "creator_set_visibility: enums::common::visibility::Visibility", + "type_info": { + "type": "String", + "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | ENUM", + "char_set": 224, + "max_size": 28 + } + }, + { + "ordinal": 10, + "name": "created_at", + "type_info": { + "type": "Timestamp", + "flags": "NOT_NULL | BINARY | TIMESTAMP", + "char_set": 63, + "max_size": 19 + } + }, + { + "ordinal": 11, + "name": "updated_at", + "type_info": { + "type": "Timestamp", + "flags": "NOT_NULL | BINARY | TIMESTAMP | ON_UPDATE_NOW", + "char_set": 63, + "max_size": 19 + } + } + ], + "parameters": { + "Right": 0 + }, + "nullable": [ + false, + false, + false, + false, + false, + false, + false, + true, + true, + false, + false, + false + ] + }, + "hash": "57a63d507ccd60824e0cf346a6aa3d69b1e34361294f7e90733a497cb8643908" +} diff --git a/.sqlx/query-6a94791c8a8f66ee54bb367a4e8c71106bbcbbb205f54c14e3657279e83dabb6.json b/.sqlx/query-6a94791c8a8f66ee54bb367a4e8c71106bbcbbb205f54c14e3657279e83dabb6.json index 1fe281c3fb..a7108cdb5d 100644 --- a/.sqlx/query-6a94791c8a8f66ee54bb367a4e8c71106bbcbbb205f54c14e3657279e83dabb6.json +++ b/.sqlx/query-6a94791c8a8f66ee54bb367a4e8c71106bbcbbb205f54c14e3657279e83dabb6.json @@ -28,7 +28,7 @@ "name": "weights_type: enums::by_table::model_weights::weights_types::WeightsType", "type_info": { "type": "VarString", - "flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE", + "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE", "char_set": 224, "max_size": 128 } @@ -38,7 +38,7 @@ "name": "weights_category: enums::by_table::model_weights::weights_category::WeightsCategory", "type_info": { "type": "VarString", - "flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE", + "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE", "char_set": 224, "max_size": 128 } @@ -78,7 +78,7 @@ "name": "creator_user_token: tokens::tokens::users::UserToken", "type_info": { "type": "VarString", - "flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE", + "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE", "char_set": 224, "max_size": 128 } @@ -98,7 +98,7 @@ "name": "creator_set_visibility: enums::common::visibility::Visibility", "type_info": { "type": "String", - "flags": "NOT_NULL | BINARY | ENUM", + "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | ENUM", "char_set": 224, "max_size": 28 } diff --git a/.sqlx/query-98d53b1732bf0b0642ac6ebae3a3a2c40f21ec732693b92ad4bda69ae2b8d5bb.json b/.sqlx/query-98d53b1732bf0b0642ac6ebae3a3a2c40f21ec732693b92ad4bda69ae2b8d5bb.json new file mode 100644 index 0000000000..e9fa1c552e --- /dev/null +++ b/.sqlx/query-98d53b1732bf0b0642ac6ebae3a3a2c40f21ec732693b92ad4bda69ae2b8d5bb.json @@ -0,0 +1,36 @@ +{ + "db_name": "MySQL", + "query": "\nSELECT\n w.token as `token: tokens::tokens::model_weights::ModelWeightToken`,\n w.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`\nFROM model_weights as w\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "token: tokens::tokens::model_weights::ModelWeightToken", + "type_info": { + "type": "VarString", + "flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 128 + } + }, + { + "ordinal": 1, + "name": "weights_type: enums::by_table::model_weights::weights_types::WeightsType", + "type_info": { + "type": "VarString", + "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 128 + } + } + ], + "parameters": { + "Right": 0 + }, + "nullable": [ + false, + false + ] + }, + "hash": "98d53b1732bf0b0642ac6ebae3a3a2c40f21ec732693b92ad4bda69ae2b8d5bb" +} diff --git a/.sqlx/query-a6ed8524fb5339fed17bec6611f8f56b6bdee35bac63c9eacbe21eb032a6a831.json b/.sqlx/query-a6ed8524fb5339fed17bec6611f8f56b6bdee35bac63c9eacbe21eb032a6a831.json index bf4a5d12ac..caa0eecbac 100644 --- a/.sqlx/query-a6ed8524fb5339fed17bec6611f8f56b6bdee35bac63c9eacbe21eb032a6a831.json +++ b/.sqlx/query-a6ed8524fb5339fed17bec6611f8f56b6bdee35bac63c9eacbe21eb032a6a831.json @@ -28,7 +28,7 @@ "name": "weights_type: enums::by_table::model_weights::weights_types::WeightsType", "type_info": { "type": "VarString", - "flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE", + "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE", "char_set": 224, "max_size": 128 } @@ -38,7 +38,7 @@ "name": "weights_category: enums::by_table::model_weights::weights_category::WeightsCategory", "type_info": { "type": "VarString", - "flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE", + "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE", "char_set": 224, "max_size": 128 } @@ -128,7 +128,7 @@ "name": "creator_set_visibility: enums::common::visibility::Visibility", "type_info": { "type": "String", - "flags": "NOT_NULL | BINARY | ENUM", + "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | ENUM", "char_set": 224, "max_size": 28 } diff --git a/.sqlx/query-d1da969247415305e6bff625150b4d2a8b3801fd27999be19cb47f5f86ea279c.json b/.sqlx/query-d1da969247415305e6bff625150b4d2a8b3801fd27999be19cb47f5f86ea279c.json new file mode 100644 index 0000000000..265506cd34 --- /dev/null +++ b/.sqlx/query-d1da969247415305e6bff625150b4d2a8b3801fd27999be19cb47f5f86ea279c.json @@ -0,0 +1,344 @@ +{ + "db_name": "MySQL", + "query": "\nSELECT\n id,\n token as `token: tokens::tokens::voice_conversion_models::VoiceConversionModelToken`,\n\n model_type as `model_type: enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType`,\n maybe_vocoder_token as `maybe_vocoder_token: tokens::tokens::vocoder_models::VocoderModelToken`,\n\n title,\n description_markdown,\n description_rendered_html,\n\n ietf_language_tag,\n ietf_primary_language_subtag,\n\n has_index_file,\n\n is_front_page_featured,\n\n original_download_url,\n original_filename,\n file_size_bytes,\n\n creator_user_token as `creator_user_token: tokens::tokens::users::UserToken`,\n\n ip_address_creation,\n ip_address_last_update,\n\n maybe_last_update_user_token as `maybe_last_update_user_token: tokens::tokens::users::UserToken`,\n\n creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n\n private_bucket_hash,\n private_bucket_object_name,\n\n is_public_listing_approved,\n is_locked_from_user_modification,\n maybe_mod_comments,\n\n maybe_migration_new_model_weights_token as `maybe_migration_new_model_weights_token: tokens::tokens::model_weights::ModelWeightToken`,\n\n version,\n\n created_at,\n updated_at,\n\n user_deleted_at,\n mod_deleted_at\n\nFROM voice_conversion_models\nWHERE\n id > ?\nORDER BY id ASC\nLIMIT ?\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": { + "type": "LongLong", + "flags": "NOT_NULL | PRIMARY_KEY | AUTO_INCREMENT", + "char_set": 63, + "max_size": 20 + } + }, + { + "ordinal": 1, + "name": "token: tokens::tokens::voice_conversion_models::VoiceConversionModelToken", + "type_info": { + "type": "VarString", + "flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 128 + } + }, + { + "ordinal": 2, + "name": "model_type: enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType", + "type_info": { + "type": "VarString", + "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 128 + } + }, + { + "ordinal": 3, + "name": "maybe_vocoder_token: tokens::tokens::vocoder_models::VocoderModelToken", + "type_info": { + "type": "VarString", + "flags": "MULTIPLE_KEY | BINARY", + "char_set": 224, + "max_size": 128 + } + }, + { + "ordinal": 4, + "name": "title", + "type_info": { + "type": "VarString", + "flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 1020 + } + }, + { + "ordinal": 5, + "name": "description_markdown", + "type_info": { + "type": "Blob", + "flags": "NOT_NULL | BLOB | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 262140 + } + }, + { + "ordinal": 6, + "name": "description_rendered_html", + "type_info": { + "type": "Blob", + "flags": "NOT_NULL | BLOB | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 262140 + } + }, + { + "ordinal": 7, + "name": "ietf_language_tag", + "type_info": { + "type": "VarString", + "flags": "NOT_NULL | BINARY", + "char_set": 224, + "max_size": 256 + } + }, + { + "ordinal": 8, + "name": "ietf_primary_language_subtag", + "type_info": { + "type": "VarString", + "flags": "NOT_NULL | BINARY", + "char_set": 224, + "max_size": 48 + } + }, + { + "ordinal": 9, + "name": "has_index_file", + "type_info": { + "type": "Tiny", + "flags": "NOT_NULL", + "char_set": 63, + "max_size": 1 + } + }, + { + "ordinal": 10, + "name": "is_front_page_featured", + "type_info": { + "type": "Tiny", + "flags": "NOT_NULL", + "char_set": 63, + "max_size": 1 + } + }, + { + "ordinal": 11, + "name": "original_download_url", + "type_info": { + "type": "VarString", + "flags": "BINARY", + "char_set": 224, + "max_size": 2048 + } + }, + { + "ordinal": 12, + "name": "original_filename", + "type_info": { + "type": "VarString", + "flags": "BINARY", + "char_set": 224, + "max_size": 1020 + } + }, + { + "ordinal": 13, + "name": "file_size_bytes", + "type_info": { + "type": "Long", + "flags": "NOT_NULL", + "char_set": 63, + "max_size": 10 + } + }, + { + "ordinal": 14, + "name": "creator_user_token: tokens::tokens::users::UserToken", + "type_info": { + "type": "VarString", + "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 128 + } + }, + { + "ordinal": 15, + "name": "ip_address_creation", + "type_info": { + "type": "VarString", + "flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 160 + } + }, + { + "ordinal": 16, + "name": "ip_address_last_update", + "type_info": { + "type": "VarString", + "flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 160 + } + }, + { + "ordinal": 17, + "name": "maybe_last_update_user_token: tokens::tokens::users::UserToken", + "type_info": { + "type": "VarString", + "flags": "BINARY", + "char_set": 224, + "max_size": 128 + } + }, + { + "ordinal": 18, + "name": "creator_set_visibility: enums::common::visibility::Visibility", + "type_info": { + "type": "String", + "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | ENUM", + "char_set": 224, + "max_size": 28 + } + }, + { + "ordinal": 19, + "name": "private_bucket_hash", + "type_info": { + "type": "String", + "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 256 + } + }, + { + "ordinal": 20, + "name": "private_bucket_object_name", + "type_info": { + "type": "VarString", + "flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 1020 + } + }, + { + "ordinal": 21, + "name": "is_public_listing_approved", + "type_info": { + "type": "Tiny", + "flags": "MULTIPLE_KEY", + "char_set": 63, + "max_size": 1 + } + }, + { + "ordinal": 22, + "name": "is_locked_from_user_modification", + "type_info": { + "type": "Tiny", + "flags": "NOT_NULL | MULTIPLE_KEY", + "char_set": 63, + "max_size": 1 + } + }, + { + "ordinal": 23, + "name": "maybe_mod_comments", + "type_info": { + "type": "VarString", + "flags": "BINARY", + "char_set": 224, + "max_size": 1020 + } + }, + { + "ordinal": 24, + "name": "maybe_migration_new_model_weights_token: tokens::tokens::model_weights::ModelWeightToken", + "type_info": { + "type": "VarString", + "flags": "UNIQUE_KEY | BINARY", + "char_set": 224, + "max_size": 128 + } + }, + { + "ordinal": 25, + "name": "version", + "type_info": { + "type": "Long", + "flags": "NOT_NULL", + "char_set": 63, + "max_size": 11 + } + }, + { + "ordinal": 26, + "name": "created_at", + "type_info": { + "type": "Timestamp", + "flags": "NOT_NULL | BINARY | TIMESTAMP", + "char_set": 63, + "max_size": 19 + } + }, + { + "ordinal": 27, + "name": "updated_at", + "type_info": { + "type": "Timestamp", + "flags": "NOT_NULL | BINARY | TIMESTAMP | ON_UPDATE_NOW", + "char_set": 63, + "max_size": 19 + } + }, + { + "ordinal": 28, + "name": "user_deleted_at", + "type_info": { + "type": "Timestamp", + "flags": "BINARY", + "char_set": 63, + "max_size": 19 + } + }, + { + "ordinal": 29, + "name": "mod_deleted_at", + "type_info": { + "type": "Timestamp", + "flags": "BINARY", + "char_set": 63, + "max_size": 19 + } + } + ], + "parameters": { + "Right": 2 + }, + "nullable": [ + false, + false, + false, + true, + false, + false, + false, + false, + false, + false, + false, + true, + true, + false, + false, + false, + false, + true, + false, + false, + false, + true, + false, + true, + true, + false, + false, + false, + true, + true + ] + }, + "hash": "d1da969247415305e6bff625150b4d2a8b3801fd27999be19cb47f5f86ea279c" +} diff --git a/.sqlx/query-f0b5767d52c389660d1859e628c746f6f33a9e1c25f21f66aeeb0784df768c8e.json b/.sqlx/query-f0b5767d52c389660d1859e628c746f6f33a9e1c25f21f66aeeb0784df768c8e.json index 7ffe2dd1d5..440dfad3e0 100644 --- a/.sqlx/query-f0b5767d52c389660d1859e628c746f6f33a9e1c25f21f66aeeb0784df768c8e.json +++ b/.sqlx/query-f0b5767d52c389660d1859e628c746f6f33a9e1c25f21f66aeeb0784df768c8e.json @@ -28,7 +28,7 @@ "name": "weights_type: enums::by_table::model_weights::weights_types::WeightsType", "type_info": { "type": "VarString", - "flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE", + "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE", "char_set": 224, "max_size": 128 } @@ -38,7 +38,7 @@ "name": "weights_category: enums::by_table::model_weights::weights_category::WeightsCategory", "type_info": { "type": "VarString", - "flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE", + "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE", "char_set": 224, "max_size": 128 } @@ -78,7 +78,7 @@ "name": "creator_user_token: tokens::tokens::users::UserToken", "type_info": { "type": "VarString", - "flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE", + "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE", "char_set": 224, "max_size": 128 } @@ -98,7 +98,7 @@ "name": "creator_set_visibility: enums::common::visibility::Visibility", "type_info": { "type": "String", - "flags": "NOT_NULL | BINARY | ENUM", + "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | ENUM", "char_set": 224, "max_size": 28 } diff --git a/.sqlx/query-f80fb6c91b897bc4a5c24cfd1e16c5975f9438c88421f19a1788531f335e75c2.json b/.sqlx/query-f80fb6c91b897bc4a5c24cfd1e16c5975f9438c88421f19a1788531f335e75c2.json new file mode 100644 index 0000000000..70e69f269b --- /dev/null +++ b/.sqlx/query-f80fb6c91b897bc4a5c24cfd1e16c5975f9438c88421f19a1788531f335e75c2.json @@ -0,0 +1,36 @@ +{ + "db_name": "MySQL", + "query": "\nSELECT\n m.token as `token: tokens::tokens::model_weights::ModelWeightToken`,\n m.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`\nFROM model_weights as m\nWHERE m.token = ?\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "token: tokens::tokens::model_weights::ModelWeightToken", + "type_info": { + "type": "VarString", + "flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 128 + } + }, + { + "ordinal": 1, + "name": "weights_type: enums::by_table::model_weights::weights_types::WeightsType", + "type_info": { + "type": "VarString", + "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 128 + } + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + false, + false + ] + }, + "hash": "f80fb6c91b897bc4a5c24cfd1e16c5975f9438c88421f19a1788531f335e75c2" +} diff --git a/.sqlx/query-fbcaa705fac9d2262a8b3ac337e30d899c8704a55999866d4cd2bce561a40065.json b/.sqlx/query-fbcaa705fac9d2262a8b3ac337e30d899c8704a55999866d4cd2bce561a40065.json new file mode 100644 index 0000000000..76ac258cc9 --- /dev/null +++ b/.sqlx/query-fbcaa705fac9d2262a8b3ac337e30d899c8704a55999866d4cd2bce561a40065.json @@ -0,0 +1,12 @@ +{ + "db_name": "MySQL", + "query": "\nINSERT INTO model_weights\nSET\n token = ?,\n weights_type = ?,\n weights_category = ?,\n title = ?,\n maybe_thumbnail_token = NULL,\n maybe_avatar_media_file_token = NULL,\n maybe_cover_media_file_token = NULL,\n description_markdown = ?,\n description_rendered_html = ?,\n creator_user_token = ?,\n creator_ip_address = ?,\n\n creator_set_visibility = ?,\n maybe_last_update_user_token = NULL,\n original_download_url = ?,\n original_filename = ?,\n file_size_bytes = ?,\n file_checksum_sha2 = \"TODO\",\n\n private_bucket_hash = \"TODO\",\n maybe_private_bucket_prefix = \"TODO\",\n maybe_private_bucket_extension = \"TODO\",\n cached_user_ratings_total_count = 0,\n cached_user_ratings_positive_count = 0,\n cached_user_ratings_negative_count = 0,\n maybe_cached_user_ratings_ratio = 0.0,\n cached_user_ratings_last_updated_at = NOW(),\n\n maybe_migration_old_model_token = ?,\n version = ?,\n created_at = ?,\n updated_at = ?,\n user_deleted_at = ?,\n mod_deleted_at = ?\n\nON DUPLICATE KEY UPDATE\n weights_type = ?,\n weights_category = ?,\n title = ?,\n maybe_thumbnail_token = NULL,\n maybe_avatar_media_file_token = NULL,\n maybe_cover_media_file_token = NULL,\n description_markdown = ?,\n description_rendered_html = ?,\n creator_user_token = ?,\n creator_ip_address = ?,\n creator_set_visibility = ?,\n maybe_last_update_user_token = NULL,\n original_download_url = ?,\n original_filename = ?,\n file_size_bytes = ?,\n file_checksum_sha2 = \"TODO\",\n private_bucket_hash = \"TODO\",\n maybe_private_bucket_prefix = \"TODO\",\n maybe_private_bucket_extension = \"TODO\",\n cached_user_ratings_total_count = 0,\n cached_user_ratings_positive_count = 0,\n cached_user_ratings_negative_count = 0,\n maybe_cached_user_ratings_ratio = 0.0,\n cached_user_ratings_last_updated_at = NOW(),\n maybe_migration_old_model_token = ?,\n version = ?,\n created_at = ?,\n updated_at = ?,\n user_deleted_at = ?,\n mod_deleted_at = ?\n ", + "describe": { + "columns": [], + "parameters": { + "Right": 35 + }, + "nullable": [] + }, + "hash": "fbcaa705fac9d2262a8b3ac337e30d899c8704a55999866d4cd2bce561a40065" +} diff --git a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/download_model_file.rs b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/download_model_file.rs index ee848d3361..295d9a1ad0 100644 --- a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/download_model_file.rs +++ b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/download_model_file.rs @@ -36,7 +36,9 @@ pub async fn download_model_file( model_record.maybe_private_bucket_prefix.as_deref(), model_record.maybe_private_bucket_extension.as_deref(), ); - model_filename = model_record.private_bucket_hash.clone() + ".".to_owned() + model_record.maybe_private_bucket_extension.as_deref().unwrap_or("bin"); + let base_name = &model_record.private_bucket_hash; + let extension = model_record.maybe_private_bucket_extension.as_deref().unwrap_or("bin"); + model_filename = format!("{base_name}.{extension}"); bucket_object_path = model_bucket_path.to_full_object_pathbuf(); } None => { From 1432c19d3b825e2fc8e37f380923d22d2e1d11ca Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Tue, 19 Dec 2023 01:47:36 -0500 Subject: [PATCH 075/124] fix all failing lints --- .../dev-database-seed/src/seeding/seed_model_weights.rs | 7 ++++--- ...te_model_weight_from_voice_conversion_download_job.rs | 5 +---- .../list/list_model_weights_for_voice_conversion.rs | 9 ++------- .../upsert_model_weight_from_voice_conversion_model.rs | 2 +- .../src/job/job_loop/determine_dependency_status.rs | 2 -- .../src/job/job_types/vc/process_single_vc_job.rs | 2 +- 6 files changed, 9 insertions(+), 18 deletions(-) diff --git a/crates/cli/dev-database-seed/src/seeding/seed_model_weights.rs b/crates/cli/dev-database-seed/src/seeding/seed_model_weights.rs index e479f275da..df11a86447 100644 --- a/crates/cli/dev-database-seed/src/seeding/seed_model_weights.rs +++ b/crates/cli/dev-database-seed/src/seeding/seed_model_weights.rs @@ -1,6 +1,6 @@ -use std::{path::Path, string}; -use errors::{anyhow, AnyhowResult}; -use log::{info, warn}; +use std::path::Path; + +use log::info; use rand::Rng; use sqlx::{MySql, Pool}; @@ -9,6 +9,7 @@ use enums::{ by_table::model_weights::{weights_category::WeightsCategory, weights_types::WeightsType}, common::visibility::Visibility, }; +use errors::{anyhow, AnyhowResult}; use filesys::file_read_bytes::file_read_bytes; use filesys::file_size::file_size; use filesys::path_to_string::path_to_string; diff --git a/crates/lib/mysql_queries/src/queries/model_weights/create/create_model_weight_from_voice_conversion_download_job.rs b/crates/lib/mysql_queries/src/queries/model_weights/create/create_model_weight_from_voice_conversion_download_job.rs index e066c68045..b2ed90edf5 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/create/create_model_weight_from_voice_conversion_download_job.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/create/create_model_weight_from_voice_conversion_download_job.rs @@ -1,11 +1,8 @@ -use std::path::Path; - use anyhow::anyhow; use sqlx::MySqlPool; + use enums::by_table::model_weights::weights_category::WeightsCategory; use enums::by_table::model_weights::weights_types::WeightsType; - -use enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType; use enums::common::visibility::Visibility; use errors::AnyhowResult; use tokens::tokens::model_weights::ModelWeightToken; diff --git a/crates/lib/mysql_queries/src/queries/model_weights/list/list_model_weights_for_voice_conversion.rs b/crates/lib/mysql_queries/src/queries/model_weights/list/list_model_weights_for_voice_conversion.rs index a902934e4f..03ce303239 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/list/list_model_weights_for_voice_conversion.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/list/list_model_weights_for_voice_conversion.rs @@ -1,18 +1,13 @@ use anyhow::anyhow; use chrono::{DateTime, Utc}; -use log::warn; -use sqlx::{MySql, MySqlPool}; +use sqlx::MySql; use sqlx::pool::PoolConnection; -use enums::by_table::model_weights::weights_types::WeightsType; -use enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType; +use enums::by_table::model_weights::weights_types::WeightsType; use enums::common::visibility::Visibility; use errors::AnyhowResult; use tokens::tokens::model_weights::ModelWeightToken; use tokens::tokens::users::UserToken; -use tokens::tokens::voice_conversion_models::VoiceConversionModelToken; - -use crate::helpers::boolean_converters::i8_to_bool; #[derive(Serialize, Clone)] pub struct ModelWeightForVoiceConversion { diff --git a/crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs b/crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs index c59b695c58..2b482dac53 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs @@ -1,5 +1,5 @@ use anyhow::anyhow; -use sqlx::{Acquire, MySql, MySqlPool, Transaction}; +use sqlx::{MySql, MySqlPool, Transaction}; use enums::by_table::model_weights::weights_category::WeightsCategory; use enums::by_table::model_weights::weights_types::WeightsType; diff --git a/crates/service/job/inference_job/src/job/job_loop/determine_dependency_status.rs b/crates/service/job/inference_job/src/job/job_loop/determine_dependency_status.rs index 65c67f01ca..a6490adfe4 100644 --- a/crates/service/job/inference_job/src/job/job_loop/determine_dependency_status.rs +++ b/crates/service/job/inference_job/src/job/job_loop/determine_dependency_status.rs @@ -5,12 +5,10 @@ use log::{info, warn}; use enums::by_table::generic_inference_jobs::inference_category::InferenceCategory; use enums::by_table::tts_models::tts_model_type::TtsModelType; -use enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType; use filesys::file_exists::file_exists; use migration::voice_conversion::query_vc_model_for_migration::{query_vc_model_for_migration, VcModel, VcModelType}; use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob; use mysql_queries::queries::tts::tts_models::get_tts_model_for_inference_improved::{get_tts_model_for_inference_improved, TtsModelForInferenceError, TtsModelForInferenceRecord}; -use mysql_queries::queries::voice_conversion::inference::get_voice_conversion_model_for_inference::{get_voice_conversion_model_for_inference, VoiceConversionModelForInference}; use crate::job::job_loop::process_single_job_error::ProcessSingleJobError; use crate::job_dependencies::JobDependencies; diff --git a/crates/service/job/inference_job/src/job/job_types/vc/process_single_vc_job.rs b/crates/service/job/inference_job/src/job/job_types/vc/process_single_vc_job.rs index 14c0d7078b..7523d642c5 100644 --- a/crates/service/job/inference_job/src/job/job_types/vc/process_single_vc_job.rs +++ b/crates/service/job/inference_job/src/job/job_types/vc/process_single_vc_job.rs @@ -25,7 +25,7 @@ pub async fn process_single_vc_job(job_dependencies: &JobDependencies, job: &Ava .await .map_err(|err| { error!("error querying vc model {model_token} : {:?}", err); - return ProcessSingleJobError::Other(anyhow!("error querying vc model {model_token} : {:?}", err)) + ProcessSingleJobError::Other(anyhow!("error querying vc model {model_token} : {:?}", err)) })?; let model = match maybe_model { From e63eef03cd8f691fde85874a38f8b9c351488609 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Tue, 19 Dec 2023 02:33:27 -0500 Subject: [PATCH 076/124] missed a few migration queries --- ...b6b06ed89c2399fd1cb03dbae36d6c35143aa30.json | 12 ++++++++++++ ...weight_from_voice_conversion_download_job.rs | 2 ++ ..._model_weight_from_voice_conversion_model.rs | 17 +++++++++++++++++ 3 files changed, 31 insertions(+) create mode 100644 .sqlx/query-760f4250fe5fb700c95ba0296b6b06ed89c2399fd1cb03dbae36d6c35143aa30.json diff --git a/.sqlx/query-760f4250fe5fb700c95ba0296b6b06ed89c2399fd1cb03dbae36d6c35143aa30.json b/.sqlx/query-760f4250fe5fb700c95ba0296b6b06ed89c2399fd1cb03dbae36d6c35143aa30.json new file mode 100644 index 0000000000..b5c31bad95 --- /dev/null +++ b/.sqlx/query-760f4250fe5fb700c95ba0296b6b06ed89c2399fd1cb03dbae36d6c35143aa30.json @@ -0,0 +1,12 @@ +{ + "db_name": "MySQL", + "query": "\nINSERT INTO model_weights_extension_voice_conversion_details\nSET\n model_weights_token = ?,\n has_index_file = ?\nON DUPLICATE KEY UPDATE\n has_index_file = ?\n ", + "describe": { + "columns": [], + "parameters": { + "Right": 3 + }, + "nullable": [] + }, + "hash": "760f4250fe5fb700c95ba0296b6b06ed89c2399fd1cb03dbae36d6c35143aa30" +} diff --git a/crates/lib/mysql_queries/src/queries/model_weights/create/create_model_weight_from_voice_conversion_download_job.rs b/crates/lib/mysql_queries/src/queries/model_weights/create/create_model_weight_from_voice_conversion_download_job.rs index b2ed90edf5..b7c14c7ae1 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/create/create_model_weight_from_voice_conversion_download_job.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/create/create_model_weight_from_voice_conversion_download_job.rs @@ -135,5 +135,7 @@ SET Err(err) => return Err(anyhow!("Mysql error: {:?}", err)), }; + transaction.commit().await?; + Ok((model_weights_record_id, weights_token)) } diff --git a/crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs b/crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs index 2b482dac53..63bcf34889 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs @@ -23,8 +23,10 @@ pub async fn upsert_model_weight_from_voice_conversion_model( let model_weight_token = create_or_generate_token(record); upsert_model_weights_record(record, &model_weight_token, &mut transaction).await?; + upsert_model_weights_extension_record(record, &model_weight_token, &mut transaction).await?; // TODO: Don't update source record with new token *unless* we're backfilling the same database. + // update_original_record(record, &model_weight_token, &mut transaction).await?; transaction.commit().await?; @@ -182,6 +184,21 @@ pub async fn upsert_model_weights_extension_record( model_weight_token: &ModelWeightToken, transaction: &mut Transaction<'_, MySql> ) -> AnyhowResult<()> { + let query = sqlx::query!( + r#" +INSERT INTO model_weights_extension_voice_conversion_details +SET + model_weights_token = ?, + has_index_file = ? +ON DUPLICATE KEY UPDATE + has_index_file = ? + "#, + &model_weight_token, + record.has_index_file, + record.has_index_file + ); + + let _r = query.execute(&mut **transaction).await?; Ok(()) } From 1ae2df8fa7a05bacc80e8a082879a30035111087 Mon Sep 17 00:00:00 2001 From: Michael Chung Date: Tue, 19 Dec 2023 02:40:42 -0500 Subject: [PATCH 077/124] working on the file manager for uploads and downloads --- crates/_types/buckets/Cargo.toml | 7 + crates/_types/buckets/src/lib.rs | 2 +- .../src/public/files/file_descriptor.rs | 163 +++++++++++++----- .../src/public/files/file_meta_data.rs | 5 + .../src/public/files/media_descriptor.rs | 0 crates/_types/buckets/src/public/files/mod.rs | 3 +- .../public/files/remote_cloud_file_manager.rs | 82 +++++++++ .../src/public/files/web_file_manager.rs | 87 ---------- crates/_types/buckets/src/public/mod.rs | 2 +- .../src/seeding/seed_media_files.rs | 8 +- 10 files changed, 224 insertions(+), 135 deletions(-) create mode 100644 crates/_types/buckets/src/public/files/file_meta_data.rs create mode 100644 crates/_types/buckets/src/public/files/media_descriptor.rs create mode 100644 crates/_types/buckets/src/public/files/remote_cloud_file_manager.rs delete mode 100644 crates/_types/buckets/src/public/files/web_file_manager.rs diff --git a/crates/_types/buckets/Cargo.toml b/crates/_types/buckets/Cargo.toml index 866ad39853..7b1e2ea24d 100644 --- a/crates/_types/buckets/Cargo.toml +++ b/crates/_types/buckets/Cargo.toml @@ -18,6 +18,13 @@ path = "src/lib.rs" crockford = { path = "../../lib/crockford" } errors = { path = "../../lib/errors" } +# probably need to have it's own module. +filesys = { path = "../../lib/files/filesys" } +hashing = { path = "../../lib/files/hashing" } +mimetypes = { path = "../../lib/files/mimetypes" } + + + # Workspace hack (faster compile times) my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" } diff --git a/crates/_types/buckets/src/lib.rs b/crates/_types/buckets/src/lib.rs index 3929dc74b2..16ed946bcb 100644 --- a/crates/_types/buckets/src/lib.rs +++ b/crates/_types/buckets/src/lib.rs @@ -10,7 +10,7 @@ // Okay to toggle #![forbid(unreachable_patterns)] -#![forbid(unused_imports)] +// #![forbid(unused_imports)] #![forbid(unused_mut)] #![forbid(unused_variables)] diff --git a/crates/_types/buckets/src/public/files/file_descriptor.rs b/crates/_types/buckets/src/public/files/file_descriptor.rs index 770bb5d0d7..04c8b0a3cd 100644 --- a/crates/_types/buckets/src/public/files/file_descriptor.rs +++ b/crates/_types/buckets/src/public/files/file_descriptor.rs @@ -1,55 +1,136 @@ // Describes the file and how it will be saved to GCBucket -#[derive(Clone)] -pub struct FileDescriptorBucketDirectory { - object_hash: String, - directory: String, -} - // where the file should be stored based off the descriptor -const WEIGHT_FILE_DIRECTORY: &str = "/weights"; + +use std::path::PathBuf; + +use crockford::crockford_entropy_lower; + +use crate::util::hashed_directory_path_long_string; + +// DEFAULT IMPLEMENTATION +const REMOTE_FILE_DIRECTORY: &str = "/implement_google_cloud_storage_bucket_name"; +// File Descriptor Steers the Bucket Directory pub trait FileDescriptor { + // By default a file belongs in the public bucket will help us figureout which bucket to use. + fn remote_directory_path(&self) -> &str { + return REMOTE_FILE_DIRECTORY; + } // this will be the type of file - // e.g .safetensors .bin .jpg - fn get_suffix(&self)->String { - return ".bin".to_string(); + // e.g requires! a period .safetensors .bin .jpg + fn get_suffix(&self)->&str { + return "implement".to_string().as_ref(); } // This will be the prefix of the media type or the weights type. // name of the weights or the name of the media type - // vall-e_prompt, loRA, sd15, sdxl - fn get_prefix(&self)->String { - return "fake_u".to_string(); + // vall-e_prompt, loRA, sd15, sdxl when implmenting add to the end + fn get_prefix(&self)->&str { + return "implement".to_string().as_ref(); + } + + // This will be ensure that the right bucket is picked + fn is_public(&self) -> bool { + true } - // This will be the token generated from the database record. - fn set_hash(&mut self, hash: String); } -// TODO FIX -// #[cfg(test)] -// mod tests { -// use crate::public::weight_files::bucket_directory::WeightFileBucketDirectory; +pub struct FileBucketDirectory<'a> { + file_object_hash: &'a str, + cloud_directory_hash: &'a str, + remote_cloud_base_directory: &'a str, + full_remote_cloud_file_path: &'a str, + file_name: &'a str, + file_descriptor: dyn FileDescriptor +} -// #[test] -// pub fn generate_new_entropy() { -// let directory = WeightFileBucketDirectory::generate_new(); -// assert_eq!(directory.get_object_hash().len(), 32); -// } +impl FileBucketDirectory<'_> { + pub fn generate_new(file_descriptor: impl FileDescriptor) -> Self { + Self::from_object_hash(file_descriptor) + } -// #[test] -// pub fn get_directory_path_str() { -// let directory = WeightFileBucketDirectory::from_object_hash("abcdefghijk"); -// assert_eq!(directory.get_directory_path_str(), "/weights/a/b/c/d/e/abcdefghijk"); -// } + fn from_object_hash(file_descriptor: dyn FileDescriptor) -> Self { + let cloud_path_entropy = crockford_entropy_lower(32); + let file_name_entropy = crockford_entropy_lower(32); -// #[test] -// pub fn get_directory_path_str_short_name() { -// let directory = WeightFileBucketDirectory::from_object_hash("foo"); -// assert_eq!(directory.get_directory_path_str(), "/weights/f/o/foo"); -// } + // gets you wiki /a/b/c/d folder structure + let middle = hashed_directory_path_long_string::hashed_directory_path_long_string(cloud_path_entropy.as_ref()); -// #[test] -// pub fn get_object_hash() { -// let hash = "abcdefghijk"; -// let directory = WeightFileBucketDirectory::from_object_hash(hash); -// assert_eq!(directory.get_object_hash(), hash); -// } -// } \ No newline at end of file + // gets you cloud bucket path e.g weights/a/b/c/d/clould_path_entropy + let remote_cloud_base_directory = format!("{}/{}{}", file_descriptor.remote_directory_path().as_ref(), middle, cloud_path_entropy.as_ref()); + + // gets you name of the file with suffix and prefix and entropy in the centre + let file_name = format!("{}_{}.{}", file_descriptor.get_prefix(), file_name_entropy.as_ref(), file_descriptor.get_suffix()); + // note: no longer optional because it's easy to know what it would be in the db explicit is better than implcit. + + // This is the full path you upload to. + let full_remote_cloud_file_path = format!("{}/{}", remote_cloud_base_directory , file_name); + Self { + file_object_hash: file_name_entropy.as_ref(), + cloud_directory_hash: cloud_path_entropy.as_ref(), + remote_cloud_base_directory: remote_cloud_base_directory.as_ref(), + full_remote_cloud_file_path: full_remote_cloud_file_path.as_ref(), + file_name:file_name.as_ref(), + file_descriptor:file_descriptor + } + } + + pub fn get_file_object_hash(&self) -> &str { + &self.file_object_hash + } + + pub fn get_cloud_directory_hash(&self) -> &str { + &self.cloud_directory_hash + } + + pub fn get_remote_cloud_base_directory(&self) -> &str { + &self.remote_cloud_base_directory + } + + pub fn get_full_remote_cloud_file_path(&self) -> &str { + &self.full_remote_cloud_file_path + } + + pub fn to_full_remote_cloud_file_path_pathbuf(&self) -> PathBuf { + PathBuf::from(&self.full_remote_cloud_file_path) + } + + pub fn get_file_name(&self) -> &str { + &self.file_name + } + + pub fn get_file_descriptor(&self) -> &dyn FileDescriptor { + &self.file_descriptor + } + +} + +#[cfg(test)] +mod tests { + + #[test] + pub fn test() { + + } + // pub fn generate_new_entropy() { + // let directory = FileDescriptorBucketDirectory::generate_new(); + // assert_eq!(directory.get_object_hash().len(), 32); + // } + + // #[test] + // pub fn get_directory_path_str() { + // let directory = FileDescriptorBucketDirectory::from_object_hash("abcdefghijk"); + // assert_eq!(directory.get_directory_path_str(), format!("/{}/a/b/c/d/e/abcdefghijk",REMOTE_FILE_DIRECTORY)); + // } + + // #[test] + // pub fn get_directory_path_str_short_name() { + // let directory = FileDescriptorBucketDirectory::from_object_hash("foo"); + // assert_eq!(directory.get_directory_path_str(), format!("/{}/f/o/foo",REMOTE_FILE_DIRECTORY)); + // } + + // #[test] + // pub fn get_object_hash() { + // let hash = "abcdefghijk"; + // let directory = FileDescriptorBucketDirectory::from_object_hash(hash); + // assert_eq!(directory.get_object_hash(), hash); + // } +} \ No newline at end of file diff --git a/crates/_types/buckets/src/public/files/file_meta_data.rs b/crates/_types/buckets/src/public/files/file_meta_data.rs new file mode 100644 index 0000000000..a2fbfd5951 --- /dev/null +++ b/crates/_types/buckets/src/public/files/file_meta_data.rs @@ -0,0 +1,5 @@ +pub struct FileMetaData { + pub file_size_bytes: u64, + pub sha256_checksum: String, + pub mimetype: String +} diff --git a/crates/_types/buckets/src/public/files/media_descriptor.rs b/crates/_types/buckets/src/public/files/media_descriptor.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/crates/_types/buckets/src/public/files/mod.rs b/crates/_types/buckets/src/public/files/mod.rs index 877a504b42..98f4625a42 100644 --- a/crates/_types/buckets/src/public/files/mod.rs +++ b/crates/_types/buckets/src/public/files/mod.rs @@ -1,3 +1,4 @@ -pub mod web_file_manager; +pub mod remote_cloud_file_manager; pub mod file_descriptor; +pub mod file_meta_data; diff --git a/crates/_types/buckets/src/public/files/remote_cloud_file_manager.rs b/crates/_types/buckets/src/public/files/remote_cloud_file_manager.rs new file mode 100644 index 0000000000..f9f327d6e3 --- /dev/null +++ b/crates/_types/buckets/src/public/files/remote_cloud_file_manager.rs @@ -0,0 +1,82 @@ + +use crate::public::files::file_descriptor::FileDescriptor; +use crate::public::files::file_meta_data::FileMetaData; + +use super::file_descriptor::FileBucketDirectory; + +use errors::AnyhowError; +use filesys::file_read_bytes::file_read_bytes; +use filesys::file_size::file_size; +use filesys::path_to_string::path_to_string; +use hashing::sha256::sha256_hash_file::sha256_hash_file; + +use mimetypes::mimetype_for_bytes::get_mimetype_for_bytes; +use mimetypes::mimetype_for_file::get_mimetype_for_file; + +// use cloud_storage::bucket_client::BucketClient; +struct WebFileManager { + // bucket_client: BucketClients, + file_descriptor: dyn FileDescriptor +} + +impl WebFileManager { + // bucket_client:BucketClients + fn new(file_descriptor: dyn FileDescriptor) -> WebFileManager { + WebFileManager { + // bucket_client: bucket_client, + file_descriptor: file_descriptor + } + } + + + // also include bucket details here + pub fn download_file(&self, system_file_path:String) { + + } + // return error or success with meta data. + pub fn upload_file(&self, system_file_path:String) -> Result { + + let file_descriptor = self.file_descriptor.clone(); + let bucket_client = self.bucket_client.clone(); + if file_descriptor.is_public() { + + } + Ok(Self::get_file_meta_data(system_file_path.clone())) + } + + // Retrieve the metadata from the file + pub fn get_file_meta_data(system_file_path:String) -> Result { + let file_size_bytes = file_size(system_file_path.clone())?; + let sha256_checksum = sha256_hash_file(system_file_path.clone())?; + + let mimetype = get_mimetype_for_bytes(&bytes).unwrap_or("application/octet-stream"); + + + FileMetaData { + file_size_bytes: file_size_bytes, + sha256_checksum: sha256_checksum, + mimetype: mimetype.to_string() + }; + } +} + + +// take in system file path to upload. +// take in system file path to download to. + +// should be able to take prefix suffix and entrpy to generate a file descriptor + +// should return this once properly uploaded. +// let file_size_bytes = file_size(weight_file_path.clone())?; +// let sha256_checksum = sha256_hash_file(weight_file_path.clone())?; + +#[cfg(test)] +mod tests { + //use crate::public::files::file_descriptor::{FileDescriptor}; + //use super::WebFileManager; + #[test] + fn test_web_file_manager() { + println!("test") + } + +} \ No newline at end of file diff --git a/crates/_types/buckets/src/public/files/web_file_manager.rs b/crates/_types/buckets/src/public/files/web_file_manager.rs deleted file mode 100644 index 67dac90909..0000000000 --- a/crates/_types/buckets/src/public/files/web_file_manager.rs +++ /dev/null @@ -1,87 +0,0 @@ -// use crockford::crockford_entropy_lower; -// use crate::util::hashed_directory_path_long_string::hashed_directory_path_long_string; -// use cloud_storage::bucket_client::BucketClient; -use crate::public::files::file_descriptor::FileDescriptor; - -pub struct WeightsDescriptor { - pub hash: String, - pub prefix: String, - pub suffix: String -} - -impl FileDescriptor for WeightsDescriptor { - fn get_suffix(&self)->String { - return self.suffix.clone(); - } - // This will be the prefix of the media type or the weights type. - // name of the weights or the name of the media type - // vall-e_prompt, loRA, sd15, sdxl - fn get_prefix(&self)->String { - return self.prefix.clone(); - } - // This will be the token generated from the database record. - fn set_hash(&mut self, hash: String) { - self.hash = hash; - } -} - -pub struct FileMetaData { - pub file_size_bytes: u64, - pub sha256_checksum: String, - pub mimetype: String -} - -// impl FileDescriptor for WeightsDescriptor { -// fn get_suffix(&self)->String { -// return ".bin".to_string(); -// } -// // This will be the prefix of the media type or the weights type. -// // name of the weights or the name of the media type -// // vall-e_prompt, loRA, sd15, sdxl -// fn get_prefix(&self)->String { -// return "fake_u".to_string(); -// } -// } - -// pub struct WebFileManager { -// pub file_descriptor: FileDescriptor -// } - - -// handles download as well. -struct WebFileManager { - // bucket_client: BucketClient, - file_descriptor: FileDescriptor -} -impl WebFileManager { - fn new(file_descriptor: dyn FileDescriptor) -> WebFileManager { - WebFileManager { - // bucket_client: bucket_client, - file_descriptor: file_descriptor - } - } - pub fn something() { - - } -} - - -// take in system file path to upload. -// take in system file path to download to. - -// should be able to take prefix suffix and entrpy to generate a file descriptor - -// should return this once properly uploaded. -// let file_size_bytes = file_size(weight_file_path.clone())?; -// let sha256_checksum = sha256_hash_file(weight_file_path.clone())?; - -#[cfg(test)] -mod tests { - //use crate::public::files::file_descriptor::{FileDescriptor}; - //use super::WebFileManager; - #[test] - fn test_web_file_manager() { - - } - -} \ No newline at end of file diff --git a/crates/_types/buckets/src/public/mod.rs b/crates/_types/buckets/src/public/mod.rs index c3f3f18b09..c357e13f4a 100644 --- a/crates/_types/buckets/src/public/mod.rs +++ b/crates/_types/buckets/src/public/mod.rs @@ -4,4 +4,4 @@ pub mod public_path; pub mod voice_conversion_results; pub mod weight_uploads; pub mod weight_files; -pub mod files; \ No newline at end of file +pub mod files; diff --git a/crates/cli/dev-database-seed/src/seeding/seed_media_files.rs b/crates/cli/dev-database-seed/src/seeding/seed_media_files.rs index 1e3f2c3c80..2e68612e1c 100644 --- a/crates/cli/dev-database-seed/src/seeding/seed_media_files.rs +++ b/crates/cli/dev-database-seed/src/seeding/seed_media_files.rs @@ -181,16 +181,16 @@ async fn seed_file_to_bucket( .extension() .map(|extension| extension.to_str()) .flatten(); - + // get the new bucket path ... let bucket_location = MediaFileBucketPath::generate_new(maybe_bucket_prefix, maybe_bucket_extension); - + let bucket_path = path_to_string(bucket_location.to_full_object_pathbuf()); info!("Reading media file: {:?}", media_file_path); - + // get meta data let bytes = file_read_bytes(media_file_path)?; let mimetype = get_mimetype_for_bytes(&bytes).unwrap_or("application/octet-stream"); - + info!("Uploading media file to bucket path: {:?}", bucket_path); let _r = bucket_clients.public.upload_file_with_content_type( From da62443522d6a8d7e6afdc6dc5eda4a916acabbc Mon Sep 17 00:00:00 2001 From: Michael Chung Date: Tue, 19 Dec 2023 02:48:41 -0500 Subject: [PATCH 078/124] Fixed some issues using a box --- .env | 2 +- Cargo.lock | 3 +++ .../buckets/src/public/files/file_descriptor.rs | 12 ++++++------ .../src/public/files/remote_cloud_file_manager.rs | 6 +++--- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/.env b/.env index a39f1b1d8d..c41492d472 100644 --- a/.env +++ b/.env @@ -76,4 +76,4 @@ TTS_HIFIGAN_SUPERRES_VOCODER_MODEL_FILENAME=hifigan_superres_twilight_33000.pt # Development key. Permissible to check in. NEWRELIC_API_KEY=c402be1c4c4216ec83d0cfc0851520cfFFFFNRAL -#STORYTELLER_ROOT="/home/tensor/code/storyteller/" # Put this in .env-secrets so that not everyone gets this setting. +STORYTELLER_ROOT="/home/tensor/code/storyteller/" # Put this in .env-secrets so that not everyone gets this setting. diff --git a/Cargo.lock b/Cargo.lock index a6a2c3ec3d..5362c2ab6d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -912,6 +912,9 @@ version = "0.0.1" dependencies = [ "crockford", "errors", + "filesys", + "hashing", + "mimetypes", "my-workspace-hack", ] diff --git a/crates/_types/buckets/src/public/files/file_descriptor.rs b/crates/_types/buckets/src/public/files/file_descriptor.rs index 04c8b0a3cd..811bbee559 100644 --- a/crates/_types/buckets/src/public/files/file_descriptor.rs +++ b/crates/_types/buckets/src/public/files/file_descriptor.rs @@ -39,7 +39,7 @@ pub struct FileBucketDirectory<'a> { remote_cloud_base_directory: &'a str, full_remote_cloud_file_path: &'a str, file_name: &'a str, - file_descriptor: dyn FileDescriptor + file_descriptor: Box } impl FileBucketDirectory<'_> { @@ -47,7 +47,7 @@ impl FileBucketDirectory<'_> { Self::from_object_hash(file_descriptor) } - fn from_object_hash(file_descriptor: dyn FileDescriptor) -> Self { + fn from_object_hash(file_descriptor: impl FileDescriptor) -> Self { let cloud_path_entropy = crockford_entropy_lower(32); let file_name_entropy = crockford_entropy_lower(32); @@ -69,7 +69,7 @@ impl FileBucketDirectory<'_> { remote_cloud_base_directory: remote_cloud_base_directory.as_ref(), full_remote_cloud_file_path: full_remote_cloud_file_path.as_ref(), file_name:file_name.as_ref(), - file_descriptor:file_descriptor + file_descriptor:Box::new(file_descriptor) } } @@ -97,9 +97,9 @@ impl FileBucketDirectory<'_> { &self.file_name } - pub fn get_file_descriptor(&self) -> &dyn FileDescriptor { - &self.file_descriptor - } + // pub fn get_file_descriptor(&self) -> &dyn FileDescriptor { + // &self.file_descriptor + // } } diff --git a/crates/_types/buckets/src/public/files/remote_cloud_file_manager.rs b/crates/_types/buckets/src/public/files/remote_cloud_file_manager.rs index f9f327d6e3..80c32e76f7 100644 --- a/crates/_types/buckets/src/public/files/remote_cloud_file_manager.rs +++ b/crates/_types/buckets/src/public/files/remote_cloud_file_manager.rs @@ -16,7 +16,7 @@ use mimetypes::mimetype_for_file::get_mimetype_for_file; // use cloud_storage::bucket_client::BucketClient; struct WebFileManager { // bucket_client: BucketClients, - file_descriptor: dyn FileDescriptor + file_descriptor: Box } impl WebFileManager { @@ -30,14 +30,14 @@ impl WebFileManager { // also include bucket details here - pub fn download_file(&self, system_file_path:String) { + pub fn download_file(&self, system_file_path:String) -> Result<(),AnyhowError> { } // return error or success with meta data. pub fn upload_file(&self, system_file_path:String) -> Result { let file_descriptor = self.file_descriptor.clone(); - let bucket_client = self.bucket_client.clone(); + // let bucket_client = self.bucket_client.clone(); if file_descriptor.is_public() { } From 775d867addaa70f02ce60b3f58484da10e8a1dc5 Mon Sep 17 00:00:00 2001 From: Michael Chung Date: Tue, 19 Dec 2023 03:05:39 -0500 Subject: [PATCH 079/124] Ok fixed compilation issues. --- .../src/public/files/file_descriptor.rs | 42 +++++++++---------- .../public/files/remote_cloud_file_manager.rs | 21 +++++----- 2 files changed, 31 insertions(+), 32 deletions(-) diff --git a/crates/_types/buckets/src/public/files/file_descriptor.rs b/crates/_types/buckets/src/public/files/file_descriptor.rs index 811bbee559..9ff72f9773 100644 --- a/crates/_types/buckets/src/public/files/file_descriptor.rs +++ b/crates/_types/buckets/src/public/files/file_descriptor.rs @@ -17,14 +17,14 @@ pub trait FileDescriptor { } // this will be the type of file // e.g requires! a period .safetensors .bin .jpg - fn get_suffix(&self)->&str { - return "implement".to_string().as_ref(); + fn get_suffix(&self)->String { + return "implement".to_string(); } // This will be the prefix of the media type or the weights type. // name of the weights or the name of the media type // vall-e_prompt, loRA, sd15, sdxl when implmenting add to the end - fn get_prefix(&self)->&str { - return "implement".to_string().as_ref(); + fn get_prefix(&self)->String { + return "implement".to_string(); } // This will be ensure that the right bucket is picked @@ -33,21 +33,21 @@ pub trait FileDescriptor { } } -pub struct FileBucketDirectory<'a> { - file_object_hash: &'a str, - cloud_directory_hash: &'a str, - remote_cloud_base_directory: &'a str, - full_remote_cloud_file_path: &'a str, - file_name: &'a str, +pub struct FileBucketDirectory { + file_object_hash: String, + cloud_directory_hash: String, + remote_cloud_base_directory: String, + full_remote_cloud_file_path: String, + file_name: String, file_descriptor: Box } -impl FileBucketDirectory<'_> { - pub fn generate_new(file_descriptor: impl FileDescriptor) -> Self { +impl FileBucketDirectory { + pub fn generate_new(file_descriptor: Box) -> Self { Self::from_object_hash(file_descriptor) } - fn from_object_hash(file_descriptor: impl FileDescriptor) -> Self { + fn from_object_hash(file_descriptor: Box) -> Self { let cloud_path_entropy = crockford_entropy_lower(32); let file_name_entropy = crockford_entropy_lower(32); @@ -55,21 +55,21 @@ impl FileBucketDirectory<'_> { let middle = hashed_directory_path_long_string::hashed_directory_path_long_string(cloud_path_entropy.as_ref()); // gets you cloud bucket path e.g weights/a/b/c/d/clould_path_entropy - let remote_cloud_base_directory = format!("{}/{}{}", file_descriptor.remote_directory_path().as_ref(), middle, cloud_path_entropy.as_ref()); + let remote_cloud_base_directory = format!("{}/{}{}", file_descriptor.remote_directory_path(), middle, cloud_path_entropy); // gets you name of the file with suffix and prefix and entropy in the centre - let file_name = format!("{}_{}.{}", file_descriptor.get_prefix(), file_name_entropy.as_ref(), file_descriptor.get_suffix()); + let file_name = format!("{}_{}.{}", file_descriptor.get_prefix(), file_name_entropy, file_descriptor.get_suffix()); // note: no longer optional because it's easy to know what it would be in the db explicit is better than implcit. // This is the full path you upload to. let full_remote_cloud_file_path = format!("{}/{}", remote_cloud_base_directory , file_name); Self { - file_object_hash: file_name_entropy.as_ref(), - cloud_directory_hash: cloud_path_entropy.as_ref(), - remote_cloud_base_directory: remote_cloud_base_directory.as_ref(), - full_remote_cloud_file_path: full_remote_cloud_file_path.as_ref(), - file_name:file_name.as_ref(), - file_descriptor:Box::new(file_descriptor) + file_object_hash: file_name_entropy, + cloud_directory_hash: cloud_path_entropy, + remote_cloud_base_directory: remote_cloud_base_directory, + full_remote_cloud_file_path: full_remote_cloud_file_path, + file_name:file_name, + file_descriptor:file_descriptor } } diff --git a/crates/_types/buckets/src/public/files/remote_cloud_file_manager.rs b/crates/_types/buckets/src/public/files/remote_cloud_file_manager.rs index 80c32e76f7..d1424d6a62 100644 --- a/crates/_types/buckets/src/public/files/remote_cloud_file_manager.rs +++ b/crates/_types/buckets/src/public/files/remote_cloud_file_manager.rs @@ -21,7 +21,7 @@ struct WebFileManager { impl WebFileManager { // bucket_client:BucketClients - fn new(file_descriptor: dyn FileDescriptor) -> WebFileManager { + fn new(file_descriptor: Box) -> WebFileManager { WebFileManager { // bucket_client: bucket_client, file_descriptor: file_descriptor @@ -30,18 +30,19 @@ impl WebFileManager { // also include bucket details here - pub fn download_file(&self, system_file_path:String) -> Result<(),AnyhowError> { + // pub fn download_file(&self, system_file_path:String) -> Result<(),AnyhowError> { - } + // } // return error or success with meta data. pub fn upload_file(&self, system_file_path:String) -> Result { - let file_descriptor = self.file_descriptor.clone(); + // let bucket_client = self.bucket_client.clone(); - if file_descriptor.is_public() { + if self.file_descriptor.is_public() { } - Ok(Self::get_file_meta_data(system_file_path.clone())) + let result = Self::get_file_meta_data(system_file_path.clone())?; + Ok(result) } // Retrieve the metadata from the file @@ -49,14 +50,15 @@ impl WebFileManager { let file_size_bytes = file_size(system_file_path.clone())?; let sha256_checksum = sha256_hash_file(system_file_path.clone())?; + let bytes = file_read_bytes(system_file_path)?; let mimetype = get_mimetype_for_bytes(&bytes).unwrap_or("application/octet-stream"); - FileMetaData { + Ok(FileMetaData { file_size_bytes: file_size_bytes, sha256_checksum: sha256_checksum, mimetype: mimetype.to_string() - }; + }) } } @@ -66,9 +68,6 @@ impl WebFileManager { // should be able to take prefix suffix and entrpy to generate a file descriptor -// should return this once properly uploaded. -// let file_size_bytes = file_size(weight_file_path.clone())?; -// let sha256_checksum = sha256_hash_file(weight_file_path.clone())?; #[cfg(test)] mod tests { From 0144c969bc3042b0e0b5081706c818223052e00e Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Tue, 19 Dec 2023 03:10:26 -0500 Subject: [PATCH 080/124] DO NOT MERGE - migration fixes Don't land the LEFT OUTER JOIN to users !!!!!! !!!!! !!!! --- Cargo.lock | 1 + crates/cli/migration-tool/Cargo.toml | 1 + crates/cli/migration-tool/src/deps.rs | 7 +++++ crates/cli/migration-tool/src/main.rs | 31 +++++++++++++++++++ ...list_model_weights_for_voice_conversion.rs | 18 +++++------ 5 files changed, 49 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index edd67bd242..46ea28a7f8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3513,6 +3513,7 @@ version = "0.0.1" dependencies = [ "buckets", "clap", + "cloud_storage", "config", "easyenv", "enums", diff --git a/crates/cli/migration-tool/Cargo.toml b/crates/cli/migration-tool/Cargo.toml index 2c7d4b065c..7018e982c7 100644 --- a/crates/cli/migration-tool/Cargo.toml +++ b/crates/cli/migration-tool/Cargo.toml @@ -15,6 +15,7 @@ path = "src/main.rs" [dependencies] # Internal buckets = { path = "../../_types/buckets" } +cloud_storage = { path = "../../lib/api_clients/cloud_storage" } config = { path = "../../lib/deprecated/config" } easyenv = { path = "../../lib/easyenv" } enums = { path = "../../_types/enums" } diff --git a/crates/cli/migration-tool/src/deps.rs b/crates/cli/migration-tool/src/deps.rs index b86d9cc35f..8e361fd4ff 100644 --- a/crates/cli/migration-tool/src/deps.rs +++ b/crates/cli/migration-tool/src/deps.rs @@ -1,6 +1,13 @@ use sqlx::{MySql, Pool}; +use cloud_storage::bucket_client::BucketClient; pub struct Deps { pub mysql_development : Pool, pub mysql_production : Pool, + + pub bucket_development_public: BucketClient, + pub bucket_development_private: BucketClient, + + pub bucket_production_public: BucketClient, + pub bucket_production_private: BucketClient, } diff --git a/crates/cli/migration-tool/src/main.rs b/crates/cli/migration-tool/src/main.rs index 4e94ccd1c0..9fdf2a3452 100644 --- a/crates/cli/migration-tool/src/main.rs +++ b/crates/cli/migration-tool/src/main.rs @@ -4,9 +4,11 @@ //! +use std::time::Duration; use log::info; use sqlx::{MySql, Pool}; use sqlx::mysql::MySqlPoolOptions; +use cloud_storage::bucket_client::BucketClient; use config::shared_constants::DEFAULT_RUST_LOG; use errors::AnyhowResult; @@ -31,6 +33,11 @@ pub async fn main() -> AnyhowResult<()> { let deps = Deps { mysql_development: get_mysql("MYSQL_DEVELOPMENT_URL").await?, mysql_production: get_mysql("MYSQL_PRODUCTION_URL").await?, + + bucket_development_public: get_bucket_client("DEVELOPMENT_PUBLIC")?, + bucket_development_private: get_bucket_client("DEVELOPMENT_PRIVATE")?, + bucket_production_public: get_bucket_client("PRODUCTION_PUBLIC")?, + bucket_production_private: get_bucket_client("PRODUCTION_PRIVATE")?, }; migrate_voice_conversion_to_weights(&deps).await?; @@ -47,3 +54,27 @@ async fn get_mysql(env_var_name: &str) -> AnyhowResult> { Ok(pool) } + +pub fn get_bucket_client(env_var_suffix: &str) -> AnyhowResult { + let env_var_suffix = env_var_suffix.to_uppercase(); + let access_key = easyenv::get_env_string_required(&format!("ACCESS_KEY_{env_var_suffix}"))?; + let secret_key = easyenv::get_env_string_required(&format!("SECRET_KEY_{env_var_suffix}"))?; + let region_name = easyenv::get_env_string_required(&format!("REGION_NAME_{env_var_suffix}"))?; + let bucket_name = easyenv::get_env_string_required(&format!("BUCKET_NAME_{env_var_suffix}"))?; + + // NB: Long timeout for dev rust builds to upload to cloud buckets. + // Unoptimized binaries sometimes take a lot of time to upload, presumably due to unoptimized code. + let bucket_timeout = easyenv::get_env_duration_seconds_or_default( + "BUCKET_TIMEOUT_SECONDS", Duration::from_secs(60 * 10)); + + info!("Configuring GCS bucket {env_var_suffix} ..."); + + Ok(BucketClient::create( + &access_key, + &secret_key, + ®ion_name, + &bucket_name, + None, + Some(bucket_timeout), + )?) +} diff --git a/crates/lib/mysql_queries/src/queries/model_weights/list/list_model_weights_for_voice_conversion.rs b/crates/lib/mysql_queries/src/queries/model_weights/list/list_model_weights_for_voice_conversion.rs index 03ce303239..3c6523f802 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/list/list_model_weights_for_voice_conversion.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/list/list_model_weights_for_voice_conversion.rs @@ -51,10 +51,10 @@ pub async fn list_model_weights_for_voice_conversion( ModelWeightForVoiceConversion { token: model.token, weight_type: model.weight_type, - creator_user_token: model.creator_user_token, - creator_username: model.creator_username, - creator_display_name: model.creator_display_name, - creator_gravatar_hash: model.creator_gravatar_hash, + creator_user_token: model.creator_user_token.unwrap_or(UserToken::new_from_str("TODO")), + creator_username: model.creator_username.unwrap_or("TODO".to_string()), + creator_display_name: model.creator_display_name.unwrap_or("TODO".to_string()), + creator_gravatar_hash: model.creator_gravatar_hash.unwrap_or("TODO".to_string()), title: model.title, ietf_language_tag: model.ietf_language_tag.unwrap_or("en".to_string()), ietf_primary_language_subtag: model.ietf_primary_language_subtag.unwrap_or("en".to_string()), @@ -89,7 +89,7 @@ SELECT FROM model_weights as w LEFT OUTER JOIN model_weights_extension_voice_conversion_details as w_extension ON w_extension.model_weights_token = w.token -JOIN users +LEFT OUTER JOIN users ON users.token = w.creator_user_token WHERE w.weights_type IN ("rvc_v2", "so_vits_svc") @@ -120,10 +120,10 @@ struct RawModelWeightForVoiceConversion { pub ietf_language_tag: Option, pub ietf_primary_language_subtag: Option, - pub creator_user_token: UserToken, - pub creator_username: String, - pub creator_display_name: String, - pub creator_gravatar_hash: String, + pub creator_user_token: Option, + pub creator_username: Option, + pub creator_display_name: Option, + pub creator_gravatar_hash: Option, pub creator_set_visibility: Visibility, From 987d98305155a6338110ac51029b427aff5364e4 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Tue, 19 Dec 2023 03:53:42 -0500 Subject: [PATCH 081/124] download / upload models --- Cargo.lock | 1 + .../public/weight_files/bucket_file_path.rs | 8 +++ crates/cli/migration-tool/Cargo.toml | 1 + .../copy_cloud_files.rs | 64 +++++++++++++++++++ .../voice_conversion_to_weights/migrate.rs | 5 +- .../voice_conversion_to_weights/mod.rs | 1 + ...odel_weight_from_voice_conversion_model.rs | 30 ++++++--- 7 files changed, 99 insertions(+), 11 deletions(-) create mode 100644 crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/copy_cloud_files.rs diff --git a/Cargo.lock b/Cargo.lock index 46ea28a7f8..6936563297 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3527,6 +3527,7 @@ dependencies = [ "sqlx", "storyteller_root", "strum", + "tempdir", "tokens", "tokio", ] diff --git a/crates/_types/buckets/src/public/weight_files/bucket_file_path.rs b/crates/_types/buckets/src/public/weight_files/bucket_file_path.rs index e1048a5494..c407346386 100644 --- a/crates/_types/buckets/src/public/weight_files/bucket_file_path.rs +++ b/crates/_types/buckets/src/public/weight_files/bucket_file_path.rs @@ -71,6 +71,14 @@ impl WeightFileBucketPath { pub fn get_basename(&self) -> &str { &self.filename } + + pub fn get_optional_prefix(&self) -> Option<&str> { + self.optional_prefix.as_deref() + } + + pub fn get_optional_extension(&self) -> Option<&str> { + self.optional_extension.as_deref() + } } #[cfg(test)] diff --git a/crates/cli/migration-tool/Cargo.toml b/crates/cli/migration-tool/Cargo.toml index 7018e982c7..4ae32a173d 100644 --- a/crates/cli/migration-tool/Cargo.toml +++ b/crates/cli/migration-tool/Cargo.toml @@ -31,6 +31,7 @@ my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" } clap = "4.4.8" log = "0.4.14" strum = { version = "0.25", features = ["derive"] } +tempdir = "0.3.7" # Async + clients tokio = { version = "1.34.0", features = ["macros"] } diff --git a/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/copy_cloud_files.rs b/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/copy_cloud_files.rs new file mode 100644 index 0000000000..965b304480 --- /dev/null +++ b/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/copy_cloud_files.rs @@ -0,0 +1,64 @@ +use tempdir::TempDir; + +use buckets::public::weight_files::bucket_file_path::WeightFileBucketPath; +use cloud_storage::bucket_path_unifier::BucketPathUnifier; +use errors::AnyhowResult; +use mysql_queries::queries::voice_conversion::migration::list_whole_voice_conversion_models_using_cursor::WholeVoiceConversionModelRecord; + +use crate::deps::Deps; + +pub async fn copy_cloud_files(model: &WholeVoiceConversionModelRecord, deps: &Deps) -> AnyhowResult { + let bucket_path = copy_model(model, deps).await?; + + if model.has_index_file { + copy_index_file(model, deps, &bucket_path).await?; + } + + Ok(bucket_path) +} + +async fn copy_model(model: &WholeVoiceConversionModelRecord, deps: &Deps) -> AnyhowResult { + let bucket_path_unifier = BucketPathUnifier::default_paths(); + + let old_model_bucket_path = bucket_path_unifier.rvc_v2_model_path(&model.private_bucket_hash); + + // TODO(bt,2023-12-19): Probably faster to stream between buckets, but whatever. + let temp_dir = TempDir::new("model_transfer")?; + let model_temp_fs_path = temp_dir.path().join("model.bin"); + + deps.bucket_production_private.download_file_to_disk(&old_model_bucket_path, &model_temp_fs_path).await?; + + let new_model_bucket_path = WeightFileBucketPath::generate_new(Some("model_"), Some(".bin")); + + deps.bucket_development_public.upload_filename_with_content_type( + &new_model_bucket_path.get_full_object_path_str(), + &model_temp_fs_path, + "application/octet-stream").await?; + + Ok(new_model_bucket_path) +} + +async fn copy_index_file(model: &WholeVoiceConversionModelRecord, deps: &Deps, bucket_path: &WeightFileBucketPath) -> AnyhowResult { + let bucket_path_unifier = BucketPathUnifier::default_paths(); + + let old_model_index_bucket_path = bucket_path_unifier.rvc_v2_model_index_path(&model.private_bucket_hash); + + // TODO(bt,2023-12-19): Probably faster to stream between buckets, but whatever. + let temp_dir = TempDir::new("model_transfer")?; + let model_temp_fs_path = temp_dir.path().join("model.bin"); + + deps.bucket_production_private.download_file_to_disk(&old_model_index_bucket_path, &model_temp_fs_path).await?; + + let new_model_bucket_path = WeightFileBucketPath::from_object_hash( + bucket_path.get_object_hash(), + Some("model_"), + Some(".index") + ); + + deps.bucket_development_public.upload_filename_with_content_type( + &new_model_bucket_path.get_full_object_path_str(), + &model_temp_fs_path, + "application/octet-stream").await?; + + Ok(new_model_bucket_path) +} diff --git a/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/migrate.rs b/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/migrate.rs index 27773e4872..844d90d772 100644 --- a/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/migrate.rs +++ b/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/migrate.rs @@ -6,6 +6,7 @@ use mysql_queries::queries::model_weights::migration::upsert_model_weight_from_v use mysql_queries::queries::voice_conversion::migration::list_whole_voice_conversion_models_using_cursor::list_whole_voice_conversion_models_using_cursor; use crate::deps::Deps; +use crate::migrations::voice_conversion_to_weights::copy_cloud_files::copy_cloud_files; const PAGE_SIZE: u64 = 10; @@ -14,7 +15,6 @@ pub async fn migrate_voice_conversion_to_weights(deps: &Deps) -> AnyhowResult<() let mut cursor = 0; loop { - let results = list_whole_voice_conversion_models_using_cursor(&deps.mysql_production, PAGE_SIZE, cursor).await?; @@ -24,7 +24,8 @@ pub async fn migrate_voice_conversion_to_weights(deps: &Deps) -> AnyhowResult<() for result in results.iter() { println!("result: {:?}\n\n", result); - upsert_model_weight_from_voice_conversion_model(result, &deps.mysql_development).await?; + let bucket_path = copy_cloud_files(result, &deps).await?; + upsert_model_weight_from_voice_conversion_model(result, &deps.mysql_development, &bucket_path).await?; } if let Some(last_id) = results.last().map(|result| result.id) { diff --git a/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/mod.rs b/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/mod.rs index 64da02492a..a2f14892d9 100644 --- a/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/mod.rs +++ b/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/mod.rs @@ -1 +1,2 @@ +pub mod copy_cloud_files; pub mod migrate; \ No newline at end of file diff --git a/crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs b/crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs index 63bcf34889..2cb86ae5e6 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs @@ -1,5 +1,6 @@ use anyhow::anyhow; use sqlx::{MySql, MySqlPool, Transaction}; +use buckets::public::weight_files::bucket_file_path::WeightFileBucketPath; use enums::by_table::model_weights::weights_category::WeightsCategory; use enums::by_table::model_weights::weights_types::WeightsType; @@ -16,13 +17,14 @@ use crate::queries::voice_conversion::migration::list_whole_voice_conversion_mod pub async fn upsert_model_weight_from_voice_conversion_model( record: &WholeVoiceConversionModelRecord, mysql_pool: &MySqlPool, + bucket_path: &WeightFileBucketPath, ) -> AnyhowResult<()> { - //let mut connection = mysql_pool.acquire().await?; + let mut transaction = mysql_pool.begin().await?; let model_weight_token = create_or_generate_token(record); - upsert_model_weights_record(record, &model_weight_token, &mut transaction).await?; + upsert_model_weights_record(record, &model_weight_token, bucket_path, &mut transaction).await?; upsert_model_weights_extension_record(record, &model_weight_token, &mut transaction).await?; // TODO: Don't update source record with new token *unless* we're backfilling the same database. @@ -43,7 +45,8 @@ pub fn create_or_generate_token(record: &WholeVoiceConversionModelRecord) -> Mod pub async fn upsert_model_weights_record( record: &WholeVoiceConversionModelRecord, model_weight_token: &ModelWeightToken, - mut transaction: &mut Transaction<'_, MySql> + bucket_path: &WeightFileBucketPath, + mut transaction: &mut Transaction<'_, MySql>, ) -> AnyhowResult<()> { let weights_type = match record.model_type { @@ -85,9 +88,9 @@ SET file_size_bytes = ?, file_checksum_sha2 = "TODO", - private_bucket_hash = "TODO", - maybe_private_bucket_prefix = "TODO", - maybe_private_bucket_extension = "TODO", + private_bucket_hash = ?, + maybe_private_bucket_prefix = ?, + maybe_private_bucket_extension = ?, cached_user_ratings_total_count = 0, cached_user_ratings_positive_count = 0, cached_user_ratings_negative_count = 0, @@ -118,9 +121,9 @@ ON DUPLICATE KEY UPDATE original_filename = ?, file_size_bytes = ?, file_checksum_sha2 = "TODO", - private_bucket_hash = "TODO", - maybe_private_bucket_prefix = "TODO", - maybe_private_bucket_extension = "TODO", + private_bucket_hash = ?, + maybe_private_bucket_prefix = ?, + maybe_private_bucket_extension = ?, cached_user_ratings_total_count = 0, cached_user_ratings_positive_count = 0, cached_user_ratings_negative_count = 0, @@ -147,6 +150,10 @@ ON DUPLICATE KEY UPDATE record.original_filename, record.file_size_bytes, + bucket_path.get_object_hash(), + bucket_path.get_optional_prefix(), + bucket_path.get_optional_extension(), + record.token.as_str(), record.version, record.created_at, @@ -166,6 +173,11 @@ ON DUPLICATE KEY UPDATE record.original_download_url, record.original_filename, record.file_size_bytes, + + bucket_path.get_object_hash(), + bucket_path.get_optional_prefix(), + bucket_path.get_optional_extension(), + record.token.as_str(), record.version, record.created_at, From 0c35dc50687a4d8fa87960ca0a7a9f18a0729d86 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Tue, 19 Dec 2023 04:15:34 -0500 Subject: [PATCH 082/124] fix inference job bucket client choice --- .../copy_cloud_files.rs | 9 +++++-- .../job/job_types/vc/rvc_v2/process_job.rs | 25 +++++++++++++++++-- .../job_types/vc/so_vits_svc/process_job.rs | 13 +++++++++- 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/copy_cloud_files.rs b/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/copy_cloud_files.rs index 965b304480..1e61186c43 100644 --- a/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/copy_cloud_files.rs +++ b/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/copy_cloud_files.rs @@ -2,7 +2,8 @@ use tempdir::TempDir; use buckets::public::weight_files::bucket_file_path::WeightFileBucketPath; use cloud_storage::bucket_path_unifier::BucketPathUnifier; -use errors::AnyhowResult; +use enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType; +use errors::{anyhow, AnyhowResult}; use mysql_queries::queries::voice_conversion::migration::list_whole_voice_conversion_models_using_cursor::WholeVoiceConversionModelRecord; use crate::deps::Deps; @@ -20,7 +21,11 @@ pub async fn copy_cloud_files(model: &WholeVoiceConversionModelRecord, deps: &De async fn copy_model(model: &WholeVoiceConversionModelRecord, deps: &Deps) -> AnyhowResult { let bucket_path_unifier = BucketPathUnifier::default_paths(); - let old_model_bucket_path = bucket_path_unifier.rvc_v2_model_path(&model.private_bucket_hash); + let old_model_bucket_path = match model.model_type { + VoiceConversionModelType::RvcV2 => bucket_path_unifier.rvc_v2_model_path(&model.private_bucket_hash), + VoiceConversionModelType::SoVitsSvc => bucket_path_unifier.so_vits_svc_model_path(&model.private_bucket_hash), + VoiceConversionModelType::SoftVc => return Err(anyhow!("we never built softvc models")), + }; // TODO(bt,2023-12-19): Probably faster to stream between buckets, but whatever. let temp_dir = TempDir::new("model_transfer")?; diff --git a/crates/service/job/inference_job/src/job/job_types/vc/rvc_v2/process_job.rs b/crates/service/job/inference_job/src/job/job_types/vc/rvc_v2/process_job.rs index 534d52b560..6d2d6c906d 100644 --- a/crates/service/job/inference_job/src/job/job_types/vc/rvc_v2/process_job.rs +++ b/crates/service/job/inference_job/src/job/job_types/vc/rvc_v2/process_job.rs @@ -22,6 +22,7 @@ use mysql_queries::queries::generic_inference::job::list_available_generic_infer use mysql_queries::queries::media_files::insert_media_file_from_voice_conversion::{insert_media_file_from_voice_conversion, InsertMediaFileArgs, VoiceConversionModelType}; use mysql_queries::queries::media_uploads::get_media_upload_for_inference::MediaUploadRecordForInference; use tokens::tokens::media_uploads::MediaUploadToken; +use tokens::tokens::model_weights::ModelWeightToken; use tokens::tokens::users::UserToken; use crate::job::job_loop::job_success_result::{JobSuccessResult, ResultEntity}; @@ -87,11 +88,21 @@ pub async fn process_job(args: RvcV2ProcessJobArgs<'_>) -> Result) -> Result) -> Result Date: Tue, 19 Dec 2023 04:48:02 -0500 Subject: [PATCH 083/124] migrate shasum --- Cargo.lock | 1 + crates/cli/migration-tool/Cargo.toml | 1 + .../copy_cloud_files.rs | 23 +++++++++----- .../voice_conversion_to_weights/migrate.rs | 4 +-- ...odel_weight_from_voice_conversion_model.rs | 31 ++++++++++++------- 5 files changed, 38 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6936563297..cd1151fdb1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3518,6 +3518,7 @@ dependencies = [ "easyenv", "enums", "errors", + "hashing", "log", "my-workspace-hack", "mysql_queries", diff --git a/crates/cli/migration-tool/Cargo.toml b/crates/cli/migration-tool/Cargo.toml index 4ae32a173d..26e243858e 100644 --- a/crates/cli/migration-tool/Cargo.toml +++ b/crates/cli/migration-tool/Cargo.toml @@ -20,6 +20,7 @@ config = { path = "../../lib/deprecated/config" } easyenv = { path = "../../lib/easyenv" } enums = { path = "../../_types/enums" } errors = { path = "../../lib/errors" } +hashing = { path = "../../lib/files/hashing" } mysql_queries = { path = "../../lib/mysql_queries" } storyteller_root = { path = "../../lib/storyteller_root" } tokens = { path = "../../_types/tokens" } diff --git a/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/copy_cloud_files.rs b/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/copy_cloud_files.rs index 1e61186c43..0474fa81e2 100644 --- a/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/copy_cloud_files.rs +++ b/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/copy_cloud_files.rs @@ -4,21 +4,23 @@ use buckets::public::weight_files::bucket_file_path::WeightFileBucketPath; use cloud_storage::bucket_path_unifier::BucketPathUnifier; use enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType; use errors::{anyhow, AnyhowResult}; +use hashing::sha256::sha256_hash_file::sha256_hash_file; +use mysql_queries::queries::model_weights::migration::upsert_model_weight_from_voice_conversion_model::CopiedFileData; use mysql_queries::queries::voice_conversion::migration::list_whole_voice_conversion_models_using_cursor::WholeVoiceConversionModelRecord; use crate::deps::Deps; -pub async fn copy_cloud_files(model: &WholeVoiceConversionModelRecord, deps: &Deps) -> AnyhowResult { - let bucket_path = copy_model(model, deps).await?; +pub async fn copy_cloud_files(model: &WholeVoiceConversionModelRecord, deps: &Deps) -> AnyhowResult { + let copied_file_data = copy_model(model, deps).await?; if model.has_index_file { - copy_index_file(model, deps, &bucket_path).await?; + copy_index_file(model, deps, &copied_file_data.bucket_path).await?; } - Ok(bucket_path) + Ok(copied_file_data) } -async fn copy_model(model: &WholeVoiceConversionModelRecord, deps: &Deps) -> AnyhowResult { +async fn copy_model(model: &WholeVoiceConversionModelRecord, deps: &Deps) -> AnyhowResult { let bucket_path_unifier = BucketPathUnifier::default_paths(); let old_model_bucket_path = match model.model_type { @@ -33,6 +35,8 @@ async fn copy_model(model: &WholeVoiceConversionModelRecord, deps: &Deps) -> Any deps.bucket_production_private.download_file_to_disk(&old_model_bucket_path, &model_temp_fs_path).await?; + let file_checksum = sha256_hash_file(&model_temp_fs_path)?; + let new_model_bucket_path = WeightFileBucketPath::generate_new(Some("model_"), Some(".bin")); deps.bucket_development_public.upload_filename_with_content_type( @@ -40,10 +44,13 @@ async fn copy_model(model: &WholeVoiceConversionModelRecord, deps: &Deps) -> Any &model_temp_fs_path, "application/octet-stream").await?; - Ok(new_model_bucket_path) + Ok(CopiedFileData { + bucket_path: new_model_bucket_path, + file_sha_hash: file_checksum, + }) } -async fn copy_index_file(model: &WholeVoiceConversionModelRecord, deps: &Deps, bucket_path: &WeightFileBucketPath) -> AnyhowResult { +async fn copy_index_file(model: &WholeVoiceConversionModelRecord, deps: &Deps, bucket_path: &WeightFileBucketPath) -> AnyhowResult<()> { let bucket_path_unifier = BucketPathUnifier::default_paths(); let old_model_index_bucket_path = bucket_path_unifier.rvc_v2_model_index_path(&model.private_bucket_hash); @@ -65,5 +72,5 @@ async fn copy_index_file(model: &WholeVoiceConversionModelRecord, deps: &Deps, b &model_temp_fs_path, "application/octet-stream").await?; - Ok(new_model_bucket_path) + Ok(()) // NB: We don't care about the path of the index file. } diff --git a/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/migrate.rs b/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/migrate.rs index 844d90d772..869808a36e 100644 --- a/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/migrate.rs +++ b/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/migrate.rs @@ -24,8 +24,8 @@ pub async fn migrate_voice_conversion_to_weights(deps: &Deps) -> AnyhowResult<() for result in results.iter() { println!("result: {:?}\n\n", result); - let bucket_path = copy_cloud_files(result, &deps).await?; - upsert_model_weight_from_voice_conversion_model(result, &deps.mysql_development, &bucket_path).await?; + let copied_data = copy_cloud_files(result, &deps).await?; + upsert_model_weight_from_voice_conversion_model(result, &deps.mysql_development, &copied_data).await?; } if let Some(last_id) = results.last().map(|result| result.id) { diff --git a/crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs b/crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs index 2cb86ae5e6..5c480ce813 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs @@ -1,7 +1,7 @@ use anyhow::anyhow; use sqlx::{MySql, MySqlPool, Transaction}; -use buckets::public::weight_files::bucket_file_path::WeightFileBucketPath; +use buckets::public::weight_files::bucket_file_path::WeightFileBucketPath; use enums::by_table::model_weights::weights_category::WeightsCategory; use enums::by_table::model_weights::weights_types::WeightsType; use enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType; @@ -10,6 +10,11 @@ use tokens::tokens::model_weights::ModelWeightToken; use crate::queries::voice_conversion::migration::list_whole_voice_conversion_models_using_cursor::WholeVoiceConversionModelRecord; +pub struct CopiedFileData { + pub bucket_path: WeightFileBucketPath, + pub file_sha_hash: String, +} + /// Migrate `voice_conversion_models` records to `model_weights` + `model_weights_extension_voice_conversion_details` records. /// This is designed to be idempotent and re-runnable. Any time we re-run the query, we should get the same result. /// This will enable us to perfect the query and get the write flows online and switched over. @@ -17,14 +22,14 @@ use crate::queries::voice_conversion::migration::list_whole_voice_conversion_mod pub async fn upsert_model_weight_from_voice_conversion_model( record: &WholeVoiceConversionModelRecord, mysql_pool: &MySqlPool, - bucket_path: &WeightFileBucketPath, + copied_data: &CopiedFileData, ) -> AnyhowResult<()> { let mut transaction = mysql_pool.begin().await?; let model_weight_token = create_or_generate_token(record); - upsert_model_weights_record(record, &model_weight_token, bucket_path, &mut transaction).await?; + upsert_model_weights_record(record, &model_weight_token, copied_data, &mut transaction).await?; upsert_model_weights_extension_record(record, &model_weight_token, &mut transaction).await?; // TODO: Don't update source record with new token *unless* we're backfilling the same database. @@ -45,7 +50,7 @@ pub fn create_or_generate_token(record: &WholeVoiceConversionModelRecord) -> Mod pub async fn upsert_model_weights_record( record: &WholeVoiceConversionModelRecord, model_weight_token: &ModelWeightToken, - bucket_path: &WeightFileBucketPath, + copied_data: &CopiedFileData, mut transaction: &mut Transaction<'_, MySql>, ) -> AnyhowResult<()> { @@ -86,7 +91,7 @@ SET original_download_url = ?, original_filename = ?, file_size_bytes = ?, - file_checksum_sha2 = "TODO", + file_checksum_sha2 = ?, private_bucket_hash = ?, maybe_private_bucket_prefix = ?, @@ -120,7 +125,7 @@ ON DUPLICATE KEY UPDATE original_download_url = ?, original_filename = ?, file_size_bytes = ?, - file_checksum_sha2 = "TODO", + file_checksum_sha2 = ?, private_bucket_hash = ?, maybe_private_bucket_prefix = ?, maybe_private_bucket_extension = ?, @@ -150,9 +155,10 @@ ON DUPLICATE KEY UPDATE record.original_filename, record.file_size_bytes, - bucket_path.get_object_hash(), - bucket_path.get_optional_prefix(), - bucket_path.get_optional_extension(), + copied_data.file_sha_hash, + copied_data.bucket_path.get_object_hash(), + copied_data.bucket_path.get_optional_prefix(), + copied_data.bucket_path.get_optional_extension(), record.token.as_str(), record.version, @@ -174,9 +180,10 @@ ON DUPLICATE KEY UPDATE record.original_filename, record.file_size_bytes, - bucket_path.get_object_hash(), - bucket_path.get_optional_prefix(), - bucket_path.get_optional_extension(), + copied_data.file_sha_hash, + copied_data.bucket_path.get_object_hash(), + copied_data.bucket_path.get_optional_prefix(), + copied_data.bucket_path.get_optional_extension(), record.token.as_str(), record.version, From 0e8aefce5cf7a2027470ae76ce4ba77cc305d630 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Tue, 19 Dec 2023 04:53:49 -0500 Subject: [PATCH 084/124] download job should also save sha --- .../create_model_weight_from_voice_conversion_download_job.rs | 4 +++- .../job_types/voice_conversion/rvc_v2/process_rvc_v2_model.rs | 3 +++ .../voice_conversion/so_vits_svc/process_so_vits_svc_model.rs | 4 +++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/crates/lib/mysql_queries/src/queries/model_weights/create/create_model_weight_from_voice_conversion_download_job.rs b/crates/lib/mysql_queries/src/queries/model_weights/create/create_model_weight_from_voice_conversion_download_job.rs index b7c14c7ae1..3f5713c141 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/create/create_model_weight_from_voice_conversion_download_job.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/create/create_model_weight_from_voice_conversion_download_job.rs @@ -21,6 +21,7 @@ pub struct CreateModelWeightArgs<'a> { pub original_download_url: &'a str, pub original_filename: &'a str, pub file_size_bytes: u64, + pub file_checksum_sha2: &'a str, pub creator_user_token: &'a UserToken, pub creator_ip_address: &'a str, @@ -72,7 +73,7 @@ SET original_download_url = ?, original_filename = ?, file_size_bytes = ?, - file_checksum_sha2 = "TODO", + file_checksum_sha2 = ?, creator_user_token = ?, creator_ip_address = ?, @@ -98,6 +99,7 @@ SET args.original_download_url, args.original_filename, args.file_size_bytes, + args.file_checksum_sha2, args.creator_user_token, args.creator_ip_address, diff --git a/crates/service/job/download_job/src/job_types/voice_conversion/rvc_v2/process_rvc_v2_model.rs b/crates/service/job/download_job/src/job_types/voice_conversion/rvc_v2/process_rvc_v2_model.rs index 979298ea93..72c55c5e30 100644 --- a/crates/service/job/download_job/src/job_types/voice_conversion/rvc_v2/process_rvc_v2_model.rs +++ b/crates/service/job/download_job/src/job_types/voice_conversion/rvc_v2/process_rvc_v2_model.rs @@ -15,6 +15,7 @@ use filesys::file_size::file_size; use filesys::safe_delete_possible_temp_file::safe_delete_possible_temp_file; use filesys::safe_delete_temp_directory::safe_delete_temp_directory; use filesys::safe_delete_temp_file::safe_delete_temp_file; +use hashing::sha256::sha256_hash_file::sha256_hash_file; use jobs_common::redis_job_status_logger::RedisJobStatusLogger; use mysql_queries::queries::generic_download::job::list_available_generic_download_jobs::AvailableDownloadJob; use mysql_queries::queries::model_weights::create::create_model_weight_from_voice_conversion_download_job::{create_model_weight_from_voice_conversion_download_job, CreateModelWeightArgs}; @@ -103,6 +104,7 @@ pub async fn process_rvc_v2_model<'a, 'b>( check_file_exists(&output_wav_path)?; let file_size_bytes = file_size(&original_model_file_path)?; + let file_checksum = sha256_hash_file(&original_model_file_path)?; // ==================== UPLOAD ORIGINAL MODEL FILE ==================== // @@ -189,6 +191,7 @@ pub async fn process_rvc_v2_model<'a, 'b>( original_download_url: &job.download_url, original_filename: &download_filename, file_size_bytes, + file_checksum_sha2: &file_checksum, creator_user_token: &job.creator_user_token, creator_ip_address: &job.creator_ip_address, creator_set_visibility: Visibility::Public, // TODO: All models default to public at start diff --git a/crates/service/job/download_job/src/job_types/voice_conversion/so_vits_svc/process_so_vits_svc_model.rs b/crates/service/job/download_job/src/job_types/voice_conversion/so_vits_svc/process_so_vits_svc_model.rs index cf6366dd62..638dfabfcf 100644 --- a/crates/service/job/download_job/src/job_types/voice_conversion/so_vits_svc/process_so_vits_svc_model.rs +++ b/crates/service/job/download_job/src/job_types/voice_conversion/so_vits_svc/process_so_vits_svc_model.rs @@ -3,9 +3,9 @@ use std::path::PathBuf; use anyhow::anyhow; use log::{error, info, warn}; use tempdir::TempDir; + use enums::by_table::model_weights::weights_category::WeightsCategory; use enums::by_table::model_weights::weights_types::WeightsType; - use enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType; use enums::common::visibility::Visibility; use errors::AnyhowResult; @@ -67,6 +67,7 @@ pub async fn process_so_vits_svc_model<'a, 'b>( check_file_exists(&output_wav_path)?; let file_size_bytes = file_size(&original_model_file_path)?; + let file_checksum = sha256_hash_file(&original_model_file_path)?; // ==================== UPLOAD ORIGINAL MODEL FILE ==================== // @@ -134,6 +135,7 @@ pub async fn process_so_vits_svc_model<'a, 'b>( original_download_url: &job.download_url, original_filename: &download_filename, file_size_bytes, + file_checksum_sha2: &file_checksum, creator_user_token: &job.creator_user_token, creator_ip_address: &job.creator_ip_address, creator_set_visibility: Visibility::Public, // TODO: All models default to public at start From fd28585e1338008752f12fd2ae48df0514c58414 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Tue, 19 Dec 2023 05:30:15 -0500 Subject: [PATCH 085/124] download to new public buckets for weights --- Cargo.lock | 1 + .../public/weight_files/bucket_file_path.rs | 68 +++++++++++++++++++ .../copy_cloud_files.rs | 13 ++-- crates/service/job/download_job/Cargo.toml | 1 + .../service/job/download_job/src/job_state.rs | 4 +- .../tts/tacotron/process_tacotron_model.rs | 2 +- .../job_types/tts/vits/process_vits_model.rs | 4 +- .../process_hifigan_softvc_vocoder.rs | 2 +- .../process_hifigan_vocoder.rs | 2 +- .../rvc_v2/process_rvc_v2_model.rs | 41 ++++++++--- .../so_vits_svc/process_so_vits_svc_model.rs | 21 ++++-- .../softvc/process_softvc_model.rs | 2 +- crates/service/job/download_job/src/main.rs | 19 ++++-- 13 files changed, 150 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cd1151fdb1..840d827860 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1877,6 +1877,7 @@ version = "0.0.1" dependencies = [ "anyhow", "bootstrap", + "buckets", "chrono", "cloud_storage", "concurrency", diff --git a/crates/_types/buckets/src/public/weight_files/bucket_file_path.rs b/crates/_types/buckets/src/public/weight_files/bucket_file_path.rs index c407346386..e0e959ae0c 100644 --- a/crates/_types/buckets/src/public/weight_files/bucket_file_path.rs +++ b/crates/_types/buckets/src/public/weight_files/bucket_file_path.rs @@ -25,6 +25,31 @@ impl PublicPath for WeightFileBucketPath {} impl WeightFileBucketPath { + // TODO(bt,2023-12-19): This is temporary standardization. Clean this up. + pub fn generate_for_svc_model() -> Self { + Self::generate_new(Some("svc_"), Some(".pt")) + } + + // TODO(bt,2023-12-19): This is temporary standardization. Clean this up. + pub fn generate_for_rvc_model() -> Self { + Self::generate_new(Some("rvc_"), Some(".pt")) + } + + // TODO(bt,2023-12-19): This is temporary standardization. Clean this up. + pub fn svc_model_file_from_object_hash(hash: &str) -> Self { + Self::from_object_hash(hash, Some("svc_"), Some(".pt")) + } + + // TODO(bt,2023-12-19): This is temporary standardization. Clean this up. + pub fn rvc_model_file_from_object_hash(hash: &str) -> Self { + Self::from_object_hash(hash, Some("rvc_"), Some(".pt")) + } + + // TODO(bt,2023-12-19): This is temporary standardization. Clean this up. + pub fn rvc_index_file_from_object_hash(hash: &str) -> Self { + Self::from_object_hash(hash, Some("rvc_"), Some(".index")) + } + pub fn generate_new(optional_prefix: Option<&str>, optional_extension: Option<&str>) -> Self { let entropy = crockford_entropy_lower(32); Self::from_object_hash(&entropy, optional_prefix, optional_extension) @@ -103,6 +128,49 @@ mod tests { assert_eq!(file.get_full_object_path_str(), "/weights/a/b/c/d/e/abcdefghijk/pre_abcdefghijk.mp4"); assert_eq!(file.get_basename(), "pre_abcdefghijk.mp4"); } + + #[test] + pub fn generate_for_rvc_model() { + let file = WeightFileBucketPath::generate_for_rvc_model(); + assert_eq!(file.get_object_hash().len(), 32); + assert_eq!(file.get_directory().get_object_hash().len(), 32); + assert_eq!(file.get_optional_prefix(), Some("rvc_")); + assert_eq!(file.get_optional_extension(), Some(".pt")); + assert!(file.get_basename().starts_with("rvc_")); + assert!(file.get_basename().ends_with(".pt")); + } + + #[test] + pub fn generate_for_svc_model() { + let file = WeightFileBucketPath::generate_for_svc_model(); + assert_eq!(file.get_object_hash().len(), 32); + assert_eq!(file.get_directory().get_object_hash().len(), 32); + assert_eq!(file.get_optional_prefix(), Some("svc_")); + assert_eq!(file.get_optional_extension(), Some(".pt")); + assert!(file.get_basename().starts_with("svc_")); + assert!(file.get_basename().ends_with(".pt")); + } + + #[test] + pub fn svc_model_file_from_object_hash() { + let file = WeightFileBucketPath::svc_model_file_from_object_hash("hashed"); + assert_eq!(file.get_full_object_path_str(), "/weights/h/a/s/h/e/hashed/svc_hashed.pt"); + assert_eq!(file.get_basename(), "svc_hashed.pt"); + } + + #[test] + pub fn rvc_model_file_from_object_hash() { + let file = WeightFileBucketPath::rvc_model_file_from_object_hash("hashed"); + assert_eq!(file.get_full_object_path_str(), "/weights/h/a/s/h/e/hashed/rvc_hashed.pt"); + assert_eq!(file.get_basename(), "rvc_hashed.pt"); + } + + #[test] + pub fn rvc_index_file_from_object_hash() { + let file = WeightFileBucketPath::rvc_index_file_from_object_hash("hashed"); + assert_eq!(file.get_full_object_path_str(), "/weights/h/a/s/h/e/hashed/rvc_hashed.index"); + assert_eq!(file.get_basename(), "rvc_hashed.index"); + } } mod without_prefix_and_extension { diff --git a/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/copy_cloud_files.rs b/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/copy_cloud_files.rs index 0474fa81e2..83d9c16f42 100644 --- a/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/copy_cloud_files.rs +++ b/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/copy_cloud_files.rs @@ -37,7 +37,11 @@ async fn copy_model(model: &WholeVoiceConversionModelRecord, deps: &Deps) -> Any let file_checksum = sha256_hash_file(&model_temp_fs_path)?; - let new_model_bucket_path = WeightFileBucketPath::generate_new(Some("model_"), Some(".bin")); + let new_model_bucket_path = match model.model_type { + VoiceConversionModelType::RvcV2 => WeightFileBucketPath::generate_for_rvc_model(), + VoiceConversionModelType::SoVitsSvc => WeightFileBucketPath::generate_for_svc_model(), + VoiceConversionModelType::SoftVc => return Err(anyhow!("we never built softvc models")), + }; deps.bucket_development_public.upload_filename_with_content_type( &new_model_bucket_path.get_full_object_path_str(), @@ -61,11 +65,8 @@ async fn copy_index_file(model: &WholeVoiceConversionModelRecord, deps: &Deps, b deps.bucket_production_private.download_file_to_disk(&old_model_index_bucket_path, &model_temp_fs_path).await?; - let new_model_bucket_path = WeightFileBucketPath::from_object_hash( - bucket_path.get_object_hash(), - Some("model_"), - Some(".index") - ); + let new_model_bucket_path = + WeightFileBucketPath::rvc_index_file_from_object_hash(bucket_path.get_object_hash()); deps.bucket_development_public.upload_filename_with_content_type( &new_model_bucket_path.get_full_object_path_str(), diff --git a/crates/service/job/download_job/Cargo.toml b/crates/service/job/download_job/Cargo.toml index 46a93e5338..0d27009e50 100644 --- a/crates/service/job/download_job/Cargo.toml +++ b/crates/service/job/download_job/Cargo.toml @@ -16,6 +16,7 @@ path = "src/main.rs" # Internal bootstrap = { path = "../../../lib/bootstrap" } +buckets = { path = "../../../_types/buckets" } cloud_storage = { path = "../../../lib/api_clients/cloud_storage" } concurrency = { path = "../../../lib/concurrency" } config = { path = "../../../lib/deprecated/config" } diff --git a/crates/service/job/download_job/src/job_state.rs b/crates/service/job/download_job/src/job_state.rs index 70dd40ee8f..14b476a1f3 100644 --- a/crates/service/job/download_job/src/job_state.rs +++ b/crates/service/job/download_job/src/job_state.rs @@ -33,7 +33,9 @@ pub struct JobState { pub redis_pool: r2d2::Pool, - pub bucket_client: BucketClient, + pub public_bucket_client: BucketClient, + pub private_bucket_client: BucketClient, + pub firehose_publisher: FirehosePublisher, pub badge_granter: BadgeGranter, diff --git a/crates/service/job/download_job/src/job_types/tts/tacotron/process_tacotron_model.rs b/crates/service/job/download_job/src/job_types/tts/tacotron/process_tacotron_model.rs index 255e4b3df4..8b5be52d66 100644 --- a/crates/service/job/download_job/src/job_types/tts/tacotron/process_tacotron_model.rs +++ b/crates/service/job/download_job/src/job_types/tts/tacotron/process_tacotron_model.rs @@ -85,7 +85,7 @@ pub async fn process_tacotron_model<'a, 'b>( // TODO(bt,2023-11-27): This method of uploading model files is super deprecated. // Try to standardize on something resembling media_files going forward. - if let Err(e) = job_state.bucket_client.upload_filename(&model_bucket_path, &file_path).await { + if let Err(e) = job_state.private_bucket_client.upload_filename(&model_bucket_path, &file_path).await { safe_delete_temp_file(&output_metadata_fs_path); safe_delete_temp_file(&file_path); safe_delete_temp_directory(&temp_dir); diff --git a/crates/service/job/download_job/src/job_types/tts/vits/process_vits_model.rs b/crates/service/job/download_job/src/job_types/tts/vits/process_vits_model.rs index e6b94eff1e..0da228408b 100644 --- a/crates/service/job/download_job/src/job_types/tts/vits/process_vits_model.rs +++ b/crates/service/job/download_job/src/job_types/tts/vits/process_vits_model.rs @@ -91,7 +91,7 @@ pub async fn process_vits_model<'a, 'b>( redis_logger.log_status("uploading VITS TTS model")?; - if let Err(err) = job_state.bucket_client.upload_filename(&model_bucket_path, &original_model_file_path).await { + if let Err(err) = job_state.private_bucket_client.upload_filename(&model_bucket_path, &original_model_file_path).await { error!("Problem uploading original model: {:?}", err); error!(" - Model file: {:?}", &original_model_file_path); error!(" - Traced model file: {:?}", &traced_model_file_path); @@ -111,7 +111,7 @@ pub async fn process_vits_model<'a, 'b>( redis_logger.log_status("uploading VITS TTS (traced) model")?; - if let Err(err) = job_state.bucket_client.upload_filename(&traced_model_bucket_path, &traced_model_file_path).await { + if let Err(err) = job_state.private_bucket_client.upload_filename(&traced_model_bucket_path, &traced_model_file_path).await { error!("Problem uploading traced model: {:?}", err); error!(" - Model file: {:?}", &original_model_file_path); error!(" - Traced model file: {:?}", &traced_model_file_path); diff --git a/crates/service/job/download_job/src/job_types/vocoder/hifigan_softvc/process_hifigan_softvc_vocoder.rs b/crates/service/job/download_job/src/job_types/vocoder/hifigan_softvc/process_hifigan_softvc_vocoder.rs index ac73745c77..ed60e70c92 100644 --- a/crates/service/job/download_job/src/job_types/vocoder/hifigan_softvc/process_hifigan_softvc_vocoder.rs +++ b/crates/service/job/download_job/src/job_types/vocoder/hifigan_softvc/process_hifigan_softvc_vocoder.rs @@ -79,7 +79,7 @@ pub async fn process_hifigan_softvc_vocoder<'a, 'b>( redis_logger.log_status("uploading hifigan model")?; - if let Err(e) = job_state.bucket_client.upload_filename(&model_bucket_path, &file_path).await { + if let Err(e) = job_state.private_bucket_client.upload_filename(&model_bucket_path, &file_path).await { safe_delete_temp_file(&output_metadata_fs_path); safe_delete_temp_file(&file_path); safe_delete_temp_directory(&temp_dir); diff --git a/crates/service/job/download_job/src/job_types/vocoder/hifigan_tacotron/process_hifigan_vocoder.rs b/crates/service/job/download_job/src/job_types/vocoder/hifigan_tacotron/process_hifigan_vocoder.rs index 610f61dc99..0154311779 100644 --- a/crates/service/job/download_job/src/job_types/vocoder/hifigan_tacotron/process_hifigan_vocoder.rs +++ b/crates/service/job/download_job/src/job_types/vocoder/hifigan_tacotron/process_hifigan_vocoder.rs @@ -79,7 +79,7 @@ pub async fn process_hifigan_vocoder<'a, 'b>( redis_logger.log_status("uploading hifigan model")?; - if let Err(e) = job_state.bucket_client.upload_filename(&model_bucket_path, &file_path).await { + if let Err(e) = job_state.private_bucket_client.upload_filename(&model_bucket_path, &file_path).await { safe_delete_temp_file(&output_metadata_fs_path); safe_delete_temp_file(&file_path); safe_delete_temp_directory(&temp_dir); diff --git a/crates/service/job/download_job/src/job_types/voice_conversion/rvc_v2/process_rvc_v2_model.rs b/crates/service/job/download_job/src/job_types/voice_conversion/rvc_v2/process_rvc_v2_model.rs index 72c55c5e30..876b211151 100644 --- a/crates/service/job/download_job/src/job_types/voice_conversion/rvc_v2/process_rvc_v2_model.rs +++ b/crates/service/job/download_job/src/job_types/voice_conversion/rvc_v2/process_rvc_v2_model.rs @@ -3,6 +3,7 @@ use std::path::PathBuf; use anyhow::anyhow; use log::{error, info, warn}; use tempdir::TempDir; +use buckets::public::weight_files::bucket_file_path::WeightFileBucketPath; use crockford::crockford_entropy_lower; use enums::by_table::model_weights::weights_category::WeightsCategory; @@ -42,7 +43,7 @@ pub async fn process_rvc_v2_model<'a, 'b>( // ==================== DOWNLOAD HUBERT ==================== // job_state.pretrained_models.rvc_v2_hubert.download_if_not_on_filesystem( - &job_state.bucket_client, + &job_state.private_bucket_client, temp_dir, ).await?; @@ -120,7 +121,7 @@ pub async fn process_rvc_v2_model<'a, 'b>( redis_logger.log_status("uploading rvc (v2) TTS model")?; - if let Err(err) = job_state.bucket_client.upload_filename(&model_bucket_path, &original_model_file_path).await { + if let Err(err) = job_state.private_bucket_client.upload_filename(&model_bucket_path, &original_model_file_path).await { error!("Problem uploading model file: {:?}", err); safe_delete_temp_file(&original_model_file_path); safe_delete_possible_temp_file(maybe_original_model_index_file_path.as_deref()); @@ -129,6 +130,18 @@ pub async fn process_rvc_v2_model<'a, 'b>( return Err(err); } + info!("Uploading to NEW model weights bucket..."); + + let new_model_bucket_path = WeightFileBucketPath::generate_for_rvc_model(); + + if let Err(err) = job_state.public_bucket_client.upload_filename(new_model_bucket_path.get_full_object_path_str(), &original_model_file_path).await { + error!("Problem uploading original model to NEW bucket: {:?}", err); + safe_delete_temp_file(&original_model_file_path); + safe_delete_temp_file(&output_wav_path); + safe_delete_temp_directory(&temp_dir); + return Err(err); + } + // ==================== UPLOAD ORIGINAL MODEL INDEX FILE ==================== // if let Some(original_index_file_path) = maybe_original_model_index_file_path.as_deref() { @@ -136,7 +149,7 @@ pub async fn process_rvc_v2_model<'a, 'b>( info!("Destination bucket path (index): {:?}", &model_index_bucket_path); - if let Err(err) = job_state.bucket_client.upload_filename(&model_index_bucket_path, &original_index_file_path).await { + if let Err(err) = job_state.private_bucket_client.upload_filename(&model_index_bucket_path, &original_index_file_path).await { error!("Problem uploading index file: {:?}", err); safe_delete_temp_file(&original_model_file_path); safe_delete_temp_file(&original_index_file_path); @@ -144,9 +157,21 @@ pub async fn process_rvc_v2_model<'a, 'b>( safe_delete_temp_directory(&temp_dir); return Err(err); } - } - // TODO(bt, 2023-12-18): Upload model weights files !! + info!("Uploading to NEW model weights (index) bucket..."); + + let new_index_bucket_path + = WeightFileBucketPath::rvc_index_file_from_object_hash(new_model_bucket_path.get_object_hash()); + + if let Err(err) = job_state.public_bucket_client.upload_filename(new_index_bucket_path.get_full_object_path_str(), &original_index_file_path).await { + error!("Problem uploading original model to NEW bucket: {:?}", err); + safe_delete_temp_file(&original_model_file_path); + safe_delete_temp_file(&original_index_file_path); + safe_delete_temp_file(&output_wav_path); + safe_delete_temp_directory(&temp_dir); + return Err(err); + } + } // ==================== DELETE DOWNLOADED FILE ==================== // @@ -196,9 +221,9 @@ pub async fn process_rvc_v2_model<'a, 'b>( creator_ip_address: &job.creator_ip_address, creator_set_visibility: Visibility::Public, // TODO: All models default to public at start has_index_file: maybe_original_model_index_file_path.is_some(), - public_bucket_hash: "TODO".to_string(), // TODO: This needs to be finished. - maybe_public_bucket_prefix: None, - maybe_public_bucket_extension: None, + public_bucket_hash: new_model_bucket_path.get_object_hash().to_string(), + maybe_public_bucket_prefix: new_model_bucket_path.get_optional_prefix().map(|s| s.to_string()), + maybe_public_bucket_extension: new_model_bucket_path.get_optional_extension().map(|s| s.to_string()), mysql_pool: &job_state.mysql_pool, }).await?; diff --git a/crates/service/job/download_job/src/job_types/voice_conversion/so_vits_svc/process_so_vits_svc_model.rs b/crates/service/job/download_job/src/job_types/voice_conversion/so_vits_svc/process_so_vits_svc_model.rs index 638dfabfcf..716858237a 100644 --- a/crates/service/job/download_job/src/job_types/voice_conversion/so_vits_svc/process_so_vits_svc_model.rs +++ b/crates/service/job/download_job/src/job_types/voice_conversion/so_vits_svc/process_so_vits_svc_model.rs @@ -3,6 +3,7 @@ use std::path::PathBuf; use anyhow::anyhow; use log::{error, info, warn}; use tempdir::TempDir; +use buckets::public::weight_files::bucket_file_path::WeightFileBucketPath; use enums::by_table::model_weights::weights_category::WeightsCategory; use enums::by_table::model_weights::weights_types::WeightsType; @@ -83,7 +84,7 @@ pub async fn process_so_vits_svc_model<'a, 'b>( redis_logger.log_status("uploading so-vits-svc TTS model")?; - if let Err(err) = job_state.bucket_client.upload_filename(&model_bucket_path, &original_model_file_path).await { + if let Err(err) = job_state.private_bucket_client.upload_filename(&model_bucket_path, &original_model_file_path).await { error!("Problem uploading original model: {:?}", err); safe_delete_temp_file(&original_model_file_path); safe_delete_temp_file(&output_wav_path); @@ -91,7 +92,17 @@ pub async fn process_so_vits_svc_model<'a, 'b>( return Err(err); } - // TODO(bt, 2023-12-18): Upload model weights files !! + info!("Uploading to NEW model weights bucket..."); + + let new_model_bucket_path = WeightFileBucketPath::generate_for_svc_model(); + + if let Err(err) = job_state.public_bucket_client.upload_filename(new_model_bucket_path.get_full_object_path_str(), &original_model_file_path).await { + error!("Problem uploading original model to NEW bucket: {:?}", err); + safe_delete_temp_file(&original_model_file_path); + safe_delete_temp_file(&output_wav_path); + safe_delete_temp_directory(&temp_dir); + return Err(err); + } // ==================== DELETE DOWNLOADED FILE ==================== // @@ -140,9 +151,9 @@ pub async fn process_so_vits_svc_model<'a, 'b>( creator_ip_address: &job.creator_ip_address, creator_set_visibility: Visibility::Public, // TODO: All models default to public at start has_index_file: false, // SVC do not have index files. - public_bucket_hash: "TODO".to_string(), // TODO: This needs to be finished. - maybe_public_bucket_prefix: None, - maybe_public_bucket_extension: None, + public_bucket_hash: new_model_bucket_path.get_object_hash().to_string(), + maybe_public_bucket_prefix: new_model_bucket_path.get_optional_prefix().map(|p| p.to_string()), + maybe_public_bucket_extension: new_model_bucket_path.get_optional_extension().map(|p| p.to_string()), mysql_pool: &job_state.mysql_pool, }).await?; diff --git a/crates/service/job/download_job/src/job_types/voice_conversion/softvc/process_softvc_model.rs b/crates/service/job/download_job/src/job_types/voice_conversion/softvc/process_softvc_model.rs index 223a428145..9135ad6f27 100644 --- a/crates/service/job/download_job/src/job_types/voice_conversion/softvc/process_softvc_model.rs +++ b/crates/service/job/download_job/src/job_types/voice_conversion/softvc/process_softvc_model.rs @@ -80,7 +80,7 @@ pub async fn process_softvc_model<'a, 'b>( redis_logger.log_status("uploading rocket vc model")?; // NB: "rocket vc" is a codename - if let Err(e) = job_state.bucket_client.upload_filename(&model_bucket_path, &file_path).await { + if let Err(e) = job_state.private_bucket_client.upload_filename(&model_bucket_path, &file_path).await { safe_delete_temp_file(&output_metadata_fs_path); safe_delete_temp_file(&file_path); safe_delete_temp_directory(&temp_dir); diff --git a/crates/service/job/download_job/src/main.rs b/crates/service/job/download_job/src/main.rs index 6967c0772f..95d93ef465 100644 --- a/crates/service/job/download_job/src/main.rs +++ b/crates/service/job/download_job/src/main.rs @@ -85,17 +85,27 @@ async fn main() -> AnyhowResult<()> { let access_key = easyenv::get_env_string_required(ENV_ACCESS_KEY)?; let secret_key = easyenv::get_env_string_required(ENV_SECRET_KEY)?; let region_name = easyenv::get_env_string_required(ENV_REGION_NAME)?; - let bucket_name = easyenv::get_env_string_required(ENV_BUCKET_NAME)?; + let private_bucket_name = easyenv::get_env_string_required("PRIVATE_BUCKET_NAME")?; + let public_bucket_name = easyenv::get_env_string_required("PUBLIC_BUCKET_NAME")?; let bucket_root = easyenv::get_env_string_required(ENV_BUCKET_ROOT)?; let bucket_timeout = easyenv::get_env_duration_seconds_or_default("BUCKET_TIMEOUT_SECONDS", Duration::from_secs(60 * 5)); - let bucket_client = BucketClient::create( + let private_bucket_client = BucketClient::create( &access_key, &secret_key, ®ion_name, - &bucket_name, + &private_bucket_name, + None, + Some(bucket_timeout), + )?; + + let public_bucket_client = BucketClient::create( + &access_key, + &secret_key, + ®ion_name, + &public_bucket_name, None, Some(bucket_timeout), )?; @@ -346,7 +356,8 @@ async fn main() -> AnyhowResult<()> { download_temp_directory: temp_directory, mysql_pool, redis_pool, - bucket_client, + private_bucket_client, + public_bucket_client, bucket_path_unifier: BucketPathUnifier::default_paths(), bucket_root_tts_model_uploads: bucket_root.to_string(), nvidia_smi_health_check_status, From 70e4af2b4cfeca4fd4cfe691fd930a3db6d1bb0a Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Tue, 19 Dec 2023 05:36:29 -0500 Subject: [PATCH 086/124] fix rvc index --- .../src/voice_conversion/query_vc_model_for_migration.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/crates/lib/migration/src/voice_conversion/query_vc_model_for_migration.rs b/crates/lib/migration/src/voice_conversion/query_vc_model_for_migration.rs index ad30dc50f3..c0db4adf8e 100644 --- a/crates/lib/migration/src/voice_conversion/query_vc_model_for_migration.rs +++ b/crates/lib/migration/src/voice_conversion/query_vc_model_for_migration.rs @@ -151,11 +151,8 @@ impl VcModel { if !model.has_index_file { return None; } - let path = WeightFileBucketPath::from_object_hash( - &model.public_bucket_hash, - model.maybe_public_bucket_prefix.as_deref(), - Some(".rvc_index")); - + // NB: Technically, we should read prefix/extension from DB. We keep index file extensions by convention, however. + let path = WeightFileBucketPath::rvc_index_file_from_object_hash(&model.public_bucket_hash); Some(PathBuf::from(path.get_full_object_path_str())) } } From 44056ee95601bc585276906a9648fe4e660c1392 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Tue, 19 Dec 2023 05:51:59 -0500 Subject: [PATCH 087/124] revert testing changes, re-codegen --- ...ff4aff39656262147e97f3e8d8eb59497fcbd5.json | 12 ------------ ...f09d0eaaa2dd5797374b4c1aa103999e8e1542.json | 12 ++++++++++++ ...34518760c3d5b10c46fb8daf96756746c01c81.json | 12 ++++++++++++ ...e30d899c8704a55999866d4cd2bce561a40065.json | 12 ------------ .../list_model_weights_for_voice_conversion.rs | 18 +++++++++--------- 5 files changed, 33 insertions(+), 33 deletions(-) delete mode 100644 .sqlx/query-2a8ac5f5cf9d955f154ef9369eff4aff39656262147e97f3e8d8eb59497fcbd5.json create mode 100644 .sqlx/query-4f36ec7baa9fa98cca25b5cc11f09d0eaaa2dd5797374b4c1aa103999e8e1542.json create mode 100644 .sqlx/query-685839dd0d875409fc1f3262e234518760c3d5b10c46fb8daf96756746c01c81.json delete mode 100644 .sqlx/query-fbcaa705fac9d2262a8b3ac337e30d899c8704a55999866d4cd2bce561a40065.json diff --git a/.sqlx/query-2a8ac5f5cf9d955f154ef9369eff4aff39656262147e97f3e8d8eb59497fcbd5.json b/.sqlx/query-2a8ac5f5cf9d955f154ef9369eff4aff39656262147e97f3e8d8eb59497fcbd5.json deleted file mode 100644 index 0f64b66b1e..0000000000 --- a/.sqlx/query-2a8ac5f5cf9d955f154ef9369eff4aff39656262147e97f3e8d8eb59497fcbd5.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "MySQL", - "query": "\nINSERT INTO model_weights\nSET\n token = ?,\n weights_type = ?,\n weights_category = ?,\n title = ?,\n\n maybe_thumbnail_token = NULL,\n maybe_avatar_media_file_token = NULL,\n maybe_cover_media_file_token = NULL,\n description_markdown = NULL,\n description_rendered_html = NULL,\n\n maybe_last_update_user_token = NULL,\n original_download_url = ?,\n original_filename = ?,\n file_size_bytes = ?,\n file_checksum_sha2 = \"TODO\",\n\n creator_user_token = ?,\n creator_ip_address = ?,\n creator_set_visibility = ?,\n\n private_bucket_hash = ?,\n maybe_private_bucket_prefix = ?,\n maybe_private_bucket_extension = ?,\n\n cached_user_ratings_total_count = 0,\n cached_user_ratings_positive_count = 0,\n cached_user_ratings_negative_count = 0,\n maybe_cached_user_ratings_ratio = 0.0,\n cached_user_ratings_last_updated_at = NOW(),\n\n maybe_migration_old_model_token = ?\n ", - "describe": { - "columns": [], - "parameters": { - "Right": 14 - }, - "nullable": [] - }, - "hash": "2a8ac5f5cf9d955f154ef9369eff4aff39656262147e97f3e8d8eb59497fcbd5" -} diff --git a/.sqlx/query-4f36ec7baa9fa98cca25b5cc11f09d0eaaa2dd5797374b4c1aa103999e8e1542.json b/.sqlx/query-4f36ec7baa9fa98cca25b5cc11f09d0eaaa2dd5797374b4c1aa103999e8e1542.json new file mode 100644 index 0000000000..8d9012e798 --- /dev/null +++ b/.sqlx/query-4f36ec7baa9fa98cca25b5cc11f09d0eaaa2dd5797374b4c1aa103999e8e1542.json @@ -0,0 +1,12 @@ +{ + "db_name": "MySQL", + "query": "\nINSERT INTO model_weights\nSET\n token = ?,\n weights_type = ?,\n weights_category = ?,\n title = ?,\n maybe_thumbnail_token = NULL,\n maybe_avatar_media_file_token = NULL,\n maybe_cover_media_file_token = NULL,\n description_markdown = ?,\n description_rendered_html = ?,\n creator_user_token = ?,\n creator_ip_address = ?,\n\n creator_set_visibility = ?,\n maybe_last_update_user_token = NULL,\n original_download_url = ?,\n original_filename = ?,\n file_size_bytes = ?,\n file_checksum_sha2 = ?,\n\n private_bucket_hash = ?,\n maybe_private_bucket_prefix = ?,\n maybe_private_bucket_extension = ?,\n cached_user_ratings_total_count = 0,\n cached_user_ratings_positive_count = 0,\n cached_user_ratings_negative_count = 0,\n maybe_cached_user_ratings_ratio = 0.0,\n cached_user_ratings_last_updated_at = NOW(),\n\n maybe_migration_old_model_token = ?,\n version = ?,\n created_at = ?,\n updated_at = ?,\n user_deleted_at = ?,\n mod_deleted_at = ?\n\nON DUPLICATE KEY UPDATE\n weights_type = ?,\n weights_category = ?,\n title = ?,\n maybe_thumbnail_token = NULL,\n maybe_avatar_media_file_token = NULL,\n maybe_cover_media_file_token = NULL,\n description_markdown = ?,\n description_rendered_html = ?,\n creator_user_token = ?,\n creator_ip_address = ?,\n creator_set_visibility = ?,\n maybe_last_update_user_token = NULL,\n original_download_url = ?,\n original_filename = ?,\n file_size_bytes = ?,\n file_checksum_sha2 = ?,\n private_bucket_hash = ?,\n maybe_private_bucket_prefix = ?,\n maybe_private_bucket_extension = ?,\n cached_user_ratings_total_count = 0,\n cached_user_ratings_positive_count = 0,\n cached_user_ratings_negative_count = 0,\n maybe_cached_user_ratings_ratio = 0.0,\n cached_user_ratings_last_updated_at = NOW(),\n maybe_migration_old_model_token = ?,\n version = ?,\n created_at = ?,\n updated_at = ?,\n user_deleted_at = ?,\n mod_deleted_at = ?\n ", + "describe": { + "columns": [], + "parameters": { + "Right": 43 + }, + "nullable": [] + }, + "hash": "4f36ec7baa9fa98cca25b5cc11f09d0eaaa2dd5797374b4c1aa103999e8e1542" +} diff --git a/.sqlx/query-685839dd0d875409fc1f3262e234518760c3d5b10c46fb8daf96756746c01c81.json b/.sqlx/query-685839dd0d875409fc1f3262e234518760c3d5b10c46fb8daf96756746c01c81.json new file mode 100644 index 0000000000..0ddaa54cff --- /dev/null +++ b/.sqlx/query-685839dd0d875409fc1f3262e234518760c3d5b10c46fb8daf96756746c01c81.json @@ -0,0 +1,12 @@ +{ + "db_name": "MySQL", + "query": "\nINSERT INTO model_weights\nSET\n token = ?,\n weights_type = ?,\n weights_category = ?,\n title = ?,\n\n maybe_thumbnail_token = NULL,\n maybe_avatar_media_file_token = NULL,\n maybe_cover_media_file_token = NULL,\n description_markdown = NULL,\n description_rendered_html = NULL,\n\n maybe_last_update_user_token = NULL,\n original_download_url = ?,\n original_filename = ?,\n file_size_bytes = ?,\n file_checksum_sha2 = ?,\n\n creator_user_token = ?,\n creator_ip_address = ?,\n creator_set_visibility = ?,\n\n private_bucket_hash = ?,\n maybe_private_bucket_prefix = ?,\n maybe_private_bucket_extension = ?,\n\n cached_user_ratings_total_count = 0,\n cached_user_ratings_positive_count = 0,\n cached_user_ratings_negative_count = 0,\n maybe_cached_user_ratings_ratio = 0.0,\n cached_user_ratings_last_updated_at = NOW(),\n\n maybe_migration_old_model_token = ?\n ", + "describe": { + "columns": [], + "parameters": { + "Right": 15 + }, + "nullable": [] + }, + "hash": "685839dd0d875409fc1f3262e234518760c3d5b10c46fb8daf96756746c01c81" +} diff --git a/.sqlx/query-fbcaa705fac9d2262a8b3ac337e30d899c8704a55999866d4cd2bce561a40065.json b/.sqlx/query-fbcaa705fac9d2262a8b3ac337e30d899c8704a55999866d4cd2bce561a40065.json deleted file mode 100644 index 76ac258cc9..0000000000 --- a/.sqlx/query-fbcaa705fac9d2262a8b3ac337e30d899c8704a55999866d4cd2bce561a40065.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "MySQL", - "query": "\nINSERT INTO model_weights\nSET\n token = ?,\n weights_type = ?,\n weights_category = ?,\n title = ?,\n maybe_thumbnail_token = NULL,\n maybe_avatar_media_file_token = NULL,\n maybe_cover_media_file_token = NULL,\n description_markdown = ?,\n description_rendered_html = ?,\n creator_user_token = ?,\n creator_ip_address = ?,\n\n creator_set_visibility = ?,\n maybe_last_update_user_token = NULL,\n original_download_url = ?,\n original_filename = ?,\n file_size_bytes = ?,\n file_checksum_sha2 = \"TODO\",\n\n private_bucket_hash = \"TODO\",\n maybe_private_bucket_prefix = \"TODO\",\n maybe_private_bucket_extension = \"TODO\",\n cached_user_ratings_total_count = 0,\n cached_user_ratings_positive_count = 0,\n cached_user_ratings_negative_count = 0,\n maybe_cached_user_ratings_ratio = 0.0,\n cached_user_ratings_last_updated_at = NOW(),\n\n maybe_migration_old_model_token = ?,\n version = ?,\n created_at = ?,\n updated_at = ?,\n user_deleted_at = ?,\n mod_deleted_at = ?\n\nON DUPLICATE KEY UPDATE\n weights_type = ?,\n weights_category = ?,\n title = ?,\n maybe_thumbnail_token = NULL,\n maybe_avatar_media_file_token = NULL,\n maybe_cover_media_file_token = NULL,\n description_markdown = ?,\n description_rendered_html = ?,\n creator_user_token = ?,\n creator_ip_address = ?,\n creator_set_visibility = ?,\n maybe_last_update_user_token = NULL,\n original_download_url = ?,\n original_filename = ?,\n file_size_bytes = ?,\n file_checksum_sha2 = \"TODO\",\n private_bucket_hash = \"TODO\",\n maybe_private_bucket_prefix = \"TODO\",\n maybe_private_bucket_extension = \"TODO\",\n cached_user_ratings_total_count = 0,\n cached_user_ratings_positive_count = 0,\n cached_user_ratings_negative_count = 0,\n maybe_cached_user_ratings_ratio = 0.0,\n cached_user_ratings_last_updated_at = NOW(),\n maybe_migration_old_model_token = ?,\n version = ?,\n created_at = ?,\n updated_at = ?,\n user_deleted_at = ?,\n mod_deleted_at = ?\n ", - "describe": { - "columns": [], - "parameters": { - "Right": 35 - }, - "nullable": [] - }, - "hash": "fbcaa705fac9d2262a8b3ac337e30d899c8704a55999866d4cd2bce561a40065" -} diff --git a/crates/lib/mysql_queries/src/queries/model_weights/list/list_model_weights_for_voice_conversion.rs b/crates/lib/mysql_queries/src/queries/model_weights/list/list_model_weights_for_voice_conversion.rs index 3c6523f802..03ce303239 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/list/list_model_weights_for_voice_conversion.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/list/list_model_weights_for_voice_conversion.rs @@ -51,10 +51,10 @@ pub async fn list_model_weights_for_voice_conversion( ModelWeightForVoiceConversion { token: model.token, weight_type: model.weight_type, - creator_user_token: model.creator_user_token.unwrap_or(UserToken::new_from_str("TODO")), - creator_username: model.creator_username.unwrap_or("TODO".to_string()), - creator_display_name: model.creator_display_name.unwrap_or("TODO".to_string()), - creator_gravatar_hash: model.creator_gravatar_hash.unwrap_or("TODO".to_string()), + creator_user_token: model.creator_user_token, + creator_username: model.creator_username, + creator_display_name: model.creator_display_name, + creator_gravatar_hash: model.creator_gravatar_hash, title: model.title, ietf_language_tag: model.ietf_language_tag.unwrap_or("en".to_string()), ietf_primary_language_subtag: model.ietf_primary_language_subtag.unwrap_or("en".to_string()), @@ -89,7 +89,7 @@ SELECT FROM model_weights as w LEFT OUTER JOIN model_weights_extension_voice_conversion_details as w_extension ON w_extension.model_weights_token = w.token -LEFT OUTER JOIN users +JOIN users ON users.token = w.creator_user_token WHERE w.weights_type IN ("rvc_v2", "so_vits_svc") @@ -120,10 +120,10 @@ struct RawModelWeightForVoiceConversion { pub ietf_language_tag: Option, pub ietf_primary_language_subtag: Option, - pub creator_user_token: Option, - pub creator_username: Option, - pub creator_display_name: Option, - pub creator_gravatar_hash: Option, + pub creator_user_token: UserToken, + pub creator_username: String, + pub creator_display_name: String, + pub creator_gravatar_hash: String, pub creator_set_visibility: Visibility, From c116ad90d08e335cc2407f471c43e4299865f472 Mon Sep 17 00:00:00 2001 From: Kasisnu <5044120+kasisnu@users.noreply.github.com> Date: Tue, 19 Dec 2023 16:45:38 +0530 Subject: [PATCH 088/124] fail voice conversion jobs after model deleted --- .../query_vc_model_for_migration.rs | 38 ++++++++++++++++--- .../job_loop/determine_dependency_status.rs | 9 ++++- 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/crates/lib/migration/src/voice_conversion/query_vc_model_for_migration.rs b/crates/lib/migration/src/voice_conversion/query_vc_model_for_migration.rs index ad30dc50f3..91028c5f26 100644 --- a/crates/lib/migration/src/voice_conversion/query_vc_model_for_migration.rs +++ b/crates/lib/migration/src/voice_conversion/query_vc_model_for_migration.rs @@ -6,28 +6,54 @@ use buckets::public::weight_files::bucket_file_path::WeightFileBucketPath; use cloud_storage::bucket_path_unifier::BucketPathUnifier; use enums::by_table::model_weights::weights_types::WeightsType; use enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType; -use errors::AnyhowResult; use jobs_common::semi_persistent_cache_dir::SemiPersistentCacheDir; -use mysql_queries::queries::model_weights::inference::get_model_weight_for_voice_conversion_inference::{get_model_weight_for_voice_conversion_inference, ModelWeightForVoiceConversionInference}; -use mysql_queries::queries::voice_conversion::inference::get_voice_conversion_model_for_inference::{get_voice_conversion_model_for_inference, VoiceConversionModelForInference}; +use mysql_queries::queries::model_weights::inference::get_model_weight_for_voice_conversion_inference::{get_model_weight_for_voice_conversion_inference, ModelWeightError, ModelWeightForVoiceConversionInference}; +use mysql_queries::queries::voice_conversion::inference::get_voice_conversion_model_for_inference::{get_voice_conversion_model_for_inference, VoiceConversionModelForInference, VoiceConversionModelForInferenceError}; use tokens::tokens::model_weights::ModelWeightToken; +#[derive(Clone, Debug)] +pub enum VcModelError { + ModelDeleted, + DatabaseError { reason: String }, +} + +impl std::fmt::Display for VcModelError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + VcModelError::ModelDeleted => write!(f, "ModelDeleted"), + VcModelError::DatabaseError { reason} => + write!(f, "Database error: {:?}", reason), + } + } +} + +impl std::error::Error for VcModelError {} + /// Query model info /// Depending on the token prefix, this does either a modern or legacy lookup. -pub async fn query_vc_model_for_migration(model_token: &str, mysql_pool: &MySqlPool) -> AnyhowResult> { +pub async fn query_vc_model_for_migration(model_token: &str, mysql_pool: &MySqlPool) -> Result, VcModelError> { // NB: This is temporary migration code as we switch from the `voice_conversion_models` table to the `model_weights` table. if model_token.starts_with(ModelWeightToken::token_prefix()) { let model_weights_token = ModelWeightToken::new_from_str(model_token); let maybe_model = get_model_weight_for_voice_conversion_inference( - &mysql_pool, &model_weights_token).await?; + &mysql_pool, &model_weights_token).await.map_err(|err| + match err { + ModelWeightError::ModelDeleted => VcModelError::ModelDeleted, + ModelWeightError::DatabaseError { reason } => VcModelError::DatabaseError { reason }, + } + )?; Ok(maybe_model .map(|model| VcModel::ModelWeight(model))) } else { let maybe_vc_model = get_voice_conversion_model_for_inference( - &mysql_pool, model_token).await?; + &mysql_pool, model_token).await.map_err(|err| + match err { + VoiceConversionModelForInferenceError::ModelDeleted => VcModelError::ModelDeleted, + VoiceConversionModelForInferenceError::DatabaseError { reason } => VcModelError::DatabaseError { reason }, + })?; Ok(maybe_vc_model .map(|model| VcModel::LegacyVoiceConversion(model))) diff --git a/crates/service/job/inference_job/src/job/job_loop/determine_dependency_status.rs b/crates/service/job/inference_job/src/job/job_loop/determine_dependency_status.rs index a6490adfe4..5af55d57fa 100644 --- a/crates/service/job/inference_job/src/job/job_loop/determine_dependency_status.rs +++ b/crates/service/job/inference_job/src/job/job_loop/determine_dependency_status.rs @@ -6,9 +6,10 @@ use log::{info, warn}; use enums::by_table::generic_inference_jobs::inference_category::InferenceCategory; use enums::by_table::tts_models::tts_model_type::TtsModelType; use filesys::file_exists::file_exists; -use migration::voice_conversion::query_vc_model_for_migration::{query_vc_model_for_migration, VcModel, VcModelType}; +use migration::voice_conversion::query_vc_model_for_migration::{query_vc_model_for_migration, VcModel, VcModelError, VcModelType}; use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob; use mysql_queries::queries::tts::tts_models::get_tts_model_for_inference_improved::{get_tts_model_for_inference_improved, TtsModelForInferenceError, TtsModelForInferenceRecord}; +use mysql_queries::queries::voice_conversion::inference::get_voice_conversion_model_for_inference::VoiceConversionModelForInferenceError; use crate::job::job_loop::process_single_job_error::ProcessSingleJobError; use crate::job_dependencies::JobDependencies; @@ -163,7 +164,11 @@ async fn get_model_record_from_cacheable_query(job_dependencies: &JobDependencie let maybe_vc_model = query_vc_model_for_migration(token, &job_dependencies.db.mysql_pool) .await - .map_err(|err| ProcessSingleJobError::Other(anyhow!("database error: {:?}", err)))?; + .map_err(|err| + match err { + VcModelError::ModelDeleted => ProcessSingleJobError::ModelDeleted, + _ => ProcessSingleJobError::Other(anyhow!("database error: {:?}", err)) + })?; match maybe_vc_model { None => MaybeInferenceModel::None, From 70694ce330d05101981e66a046c06d6582118eb6 Mon Sep 17 00:00:00 2001 From: Michael Chung Date: Tue, 19 Dec 2023 17:43:24 -0500 Subject: [PATCH 089/124] Need to replace the hashing function with a new one and merge master. --- crates/_types/buckets/Cargo.toml | 5 +++-- .../src/seeding/seed_media_files.rs | 2 +- .../cloud_storage/src/bucket_client.rs | 2 +- crates/lib/api_clients/cloud_storage/src/lib.rs | 1 + .../src/remote_file_manager}/file_descriptor.rs | 17 +++++++---------- .../src/remote_file_manager}/file_meta_data.rs | 0 .../remote_file_manager}/media_descriptor.rs | 0 .../src/remote_file_manager}/mod.rs | 5 ++++- .../remote_cloud_file_manager.rs | 17 +++++++---------- .../remote_file_manager}/weights_descriptor.rs | 0 10 files changed, 24 insertions(+), 25 deletions(-) rename crates/{_types/buckets/src/public/files => lib/api_clients/cloud_storage/src/remote_file_manager}/file_descriptor.rs (93%) rename crates/{_types/buckets/src/public/files => lib/api_clients/cloud_storage/src/remote_file_manager}/file_meta_data.rs (100%) rename crates/{_types/buckets/src/public/files => lib/api_clients/cloud_storage/src/remote_file_manager}/media_descriptor.rs (100%) rename crates/{_types/buckets/src/public/files => lib/api_clients/cloud_storage/src/remote_file_manager}/mod.rs (61%) rename crates/{_types/buckets/src/public/files => lib/api_clients/cloud_storage/src/remote_file_manager}/remote_cloud_file_manager.rs (89%) rename crates/{_types/buckets/src/public/files => lib/api_clients/cloud_storage/src/remote_file_manager}/weights_descriptor.rs (100%) diff --git a/crates/_types/buckets/Cargo.toml b/crates/_types/buckets/Cargo.toml index 7b1e2ea24d..218cd6be37 100644 --- a/crates/_types/buckets/Cargo.toml +++ b/crates/_types/buckets/Cargo.toml @@ -22,8 +22,9 @@ errors = { path = "../../lib/errors" } filesys = { path = "../../lib/files/filesys" } hashing = { path = "../../lib/files/hashing" } mimetypes = { path = "../../lib/files/mimetypes" } - - +# have to add this to it's own module..... +# buckets = { path = "../../_types/buckets" } +# cloud_storage = { path = "../../lib/api_clients/cloud_storage" } # Workspace hack (faster compile times) my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" } diff --git a/crates/cli/dev-database-seed/src/seeding/seed_media_files.rs b/crates/cli/dev-database-seed/src/seeding/seed_media_files.rs index 2e68612e1c..8036018f83 100644 --- a/crates/cli/dev-database-seed/src/seeding/seed_media_files.rs +++ b/crates/cli/dev-database-seed/src/seeding/seed_media_files.rs @@ -106,7 +106,7 @@ async fn seed_model( let mut bucket_hash = "NOT_UPLOADED_BY_SEED_TOOL".to_string(); let mut maybe_bucket_prefix = None; let mut maybe_bucket_extension = None; - + if media_file_exists(mysql_pool, media_file_token).await? { info!("Media file already seeded: {:?}", media_file_token); return Ok(()) diff --git a/crates/lib/api_clients/cloud_storage/src/bucket_client.rs b/crates/lib/api_clients/cloud_storage/src/bucket_client.rs index 78632d7d1b..677507c110 100644 --- a/crates/lib/api_clients/cloud_storage/src/bucket_client.rs +++ b/crates/lib/api_clients/cloud_storage/src/bucket_client.rs @@ -14,7 +14,7 @@ use tokio::io::AsyncReadExt; #[derive(Clone)] pub struct BucketClient { bucket: Bucket, - + /// If set, put all files under this root path. optional_bucket_root: Option, } diff --git a/crates/lib/api_clients/cloud_storage/src/lib.rs b/crates/lib/api_clients/cloud_storage/src/lib.rs index 6c74cb023f..da2cb76964 100644 --- a/crates/lib/api_clients/cloud_storage/src/lib.rs +++ b/crates/lib/api_clients/cloud_storage/src/lib.rs @@ -1,2 +1,3 @@ pub mod bucket_client; pub mod bucket_path_unifier; +pub mod remote_file_manager; \ No newline at end of file diff --git a/crates/_types/buckets/src/public/files/file_descriptor.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/file_descriptor.rs similarity index 93% rename from crates/_types/buckets/src/public/files/file_descriptor.rs rename to crates/lib/api_clients/cloud_storage/src/remote_file_manager/file_descriptor.rs index 9ff72f9773..b9b186a4d2 100644 --- a/crates/_types/buckets/src/public/files/file_descriptor.rs +++ b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/file_descriptor.rs @@ -2,9 +2,7 @@ // where the file should be stored based off the descriptor use std::path::PathBuf; - use crockford::crockford_entropy_lower; - use crate::util::hashed_directory_path_long_string; // DEFAULT IMPLEMENTATION @@ -22,7 +20,7 @@ pub trait FileDescriptor { } // This will be the prefix of the media type or the weights type. // name of the weights or the name of the media type - // vall-e_prompt, loRA, sd15, sdxl when implmenting add to the end + // vall-e_prompt, loRA, sd15, sdxl when implmenting add to the end fn get_prefix(&self)->String { return "implement".to_string(); } @@ -97,8 +95,8 @@ impl FileBucketDirectory { &self.file_name } - // pub fn get_file_descriptor(&self) -> &dyn FileDescriptor { - // &self.file_descriptor + // pub fn get_file_descriptor(&self) -> Box { + // self.file_descriptor // } } @@ -107,13 +105,12 @@ impl FileBucketDirectory { mod tests { #[test] - pub fn test() { + pub fn test() {} + pub fn generate_new_entropy() { + let directory = FileDescriptorBucketDirectory::generate_new(); + assert_eq!(directory.get_object_hash().len(), 32); } - // pub fn generate_new_entropy() { - // let directory = FileDescriptorBucketDirectory::generate_new(); - // assert_eq!(directory.get_object_hash().len(), 32); - // } // #[test] // pub fn get_directory_path_str() { diff --git a/crates/_types/buckets/src/public/files/file_meta_data.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/file_meta_data.rs similarity index 100% rename from crates/_types/buckets/src/public/files/file_meta_data.rs rename to crates/lib/api_clients/cloud_storage/src/remote_file_manager/file_meta_data.rs diff --git a/crates/_types/buckets/src/public/files/media_descriptor.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/media_descriptor.rs similarity index 100% rename from crates/_types/buckets/src/public/files/media_descriptor.rs rename to crates/lib/api_clients/cloud_storage/src/remote_file_manager/media_descriptor.rs diff --git a/crates/_types/buckets/src/public/files/mod.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/mod.rs similarity index 61% rename from crates/_types/buckets/src/public/files/mod.rs rename to crates/lib/api_clients/cloud_storage/src/remote_file_manager/mod.rs index 98f4625a42..d818e2bc52 100644 --- a/crates/_types/buckets/src/public/files/mod.rs +++ b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/mod.rs @@ -1,4 +1,7 @@ pub mod remote_cloud_file_manager; -pub mod file_descriptor; + pub mod file_meta_data; +pub mod file_descriptor; +pub mod media_descriptor; +pub mod weights_descriptor; \ No newline at end of file diff --git a/crates/_types/buckets/src/public/files/remote_cloud_file_manager.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_file_manager.rs similarity index 89% rename from crates/_types/buckets/src/public/files/remote_cloud_file_manager.rs rename to crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_file_manager.rs index d1424d6a62..992968af46 100644 --- a/crates/_types/buckets/src/public/files/remote_cloud_file_manager.rs +++ b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_file_manager.rs @@ -13,7 +13,6 @@ use hashing::sha256::sha256_hash_file::sha256_hash_file; use mimetypes::mimetype_for_bytes::get_mimetype_for_bytes; use mimetypes::mimetype_for_file::get_mimetype_for_file; -// use cloud_storage::bucket_client::BucketClient; struct WebFileManager { // bucket_client: BucketClients, file_descriptor: Box @@ -28,18 +27,18 @@ impl WebFileManager { } } - + // also include bucket details here - // pub fn download_file(&self, system_file_path:String) -> Result<(),AnyhowError> { - - // } + pub fn download_file(&self, system_file_path:String) -> Result<(),AnyhowError> { + + } // return error or success with meta data. pub fn upload_file(&self, system_file_path:String) -> Result { - - // let bucket_client = self.bucket_client.clone(); if self.file_descriptor.is_public() { + }else { + // use private bucket client } let result = Self::get_file_meta_data(system_file_path.clone())?; Ok(result) @@ -51,8 +50,7 @@ impl WebFileManager { let sha256_checksum = sha256_hash_file(system_file_path.clone())?; let bytes = file_read_bytes(system_file_path)?; - let mimetype = get_mimetype_for_bytes(&bytes).unwrap_or("application/octet-stream"); - + let mimetype: &str = get_mimetype_for_bytes(&bytes).unwrap_or("application/octet-stream"); Ok(FileMetaData { file_size_bytes: file_size_bytes, @@ -68,7 +66,6 @@ impl WebFileManager { // should be able to take prefix suffix and entrpy to generate a file descriptor - #[cfg(test)] mod tests { //use crate::public::files::file_descriptor::{FileDescriptor}; diff --git a/crates/_types/buckets/src/public/files/weights_descriptor.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/weights_descriptor.rs similarity index 100% rename from crates/_types/buckets/src/public/files/weights_descriptor.rs rename to crates/lib/api_clients/cloud_storage/src/remote_file_manager/weights_descriptor.rs From 61f30618b01400e493a6d6d6e184b49b4f9b5263 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Tue, 19 Dec 2023 20:43:27 -0500 Subject: [PATCH 090/124] fix/cleanup some paths, fix tests --- .../buckets/src/util/hash_to_bucket_path.rs | 49 ------------------- .../src/util/hash_to_bucket_path_string.rs | 35 ------------- .../hashed_directory_path_short_string.rs | 1 + crates/_types/buckets/src/util/mod.rs | 2 - .../query_vc_model_for_migration.rs | 2 +- .../service/job/w2l_download_job/src/main.rs | 9 ++-- .../w2l/enqueue_infer_w2l_with_uploads.rs | 17 ++++--- 7 files changed, 16 insertions(+), 99 deletions(-) delete mode 100644 crates/_types/buckets/src/util/hash_to_bucket_path.rs delete mode 100644 crates/_types/buckets/src/util/hash_to_bucket_path_string.rs diff --git a/crates/_types/buckets/src/util/hash_to_bucket_path.rs b/crates/_types/buckets/src/util/hash_to_bucket_path.rs deleted file mode 100644 index dc94c09311..0000000000 --- a/crates/_types/buckets/src/util/hash_to_bucket_path.rs +++ /dev/null @@ -1,49 +0,0 @@ -use std::path::PathBuf; - -use errors::AnyhowResult; -use errors::bail; - -#[deprecated(note = "this is a messy function and should be avoided")] -pub (crate) fn hash_to_bucket_path(file_hash: &str, - optional_root_directory: Option<&str>) - -> AnyhowResult -{ - if file_hash.len() < 4 { - bail!("File length is too short"); - } - - let root_directory = optional_root_directory - .map(|root| PathBuf::from(root.to_string())) - .unwrap_or(PathBuf::from("/")); - - let file_path = format!( - "{}/{}/{}/{}", - &file_hash[0..1], - &file_hash[1..2], - &file_hash[2..3], - &file_hash, - ); - - Ok(root_directory.join(file_path)) -} - -#[cfg(test)] -mod tests { - use std::path::PathBuf; - - use crate::util::hash_to_bucket_path::hash_to_bucket_path; - - #[test] - fn test_bucket_without_root() { - assert_eq!( - hash_to_bucket_path("abcdefg", None).unwrap(), - PathBuf::from("/a/b/c/abcdefg")); - } - - #[test] - fn test_bucket_with_root() { - assert_eq!( - hash_to_bucket_path("abcdefg", Some("/root")).unwrap(), - PathBuf::from("/root/a/b/c/abcdefg")); - } -} diff --git a/crates/_types/buckets/src/util/hash_to_bucket_path_string.rs b/crates/_types/buckets/src/util/hash_to_bucket_path_string.rs deleted file mode 100644 index ad715cd9d3..0000000000 --- a/crates/_types/buckets/src/util/hash_to_bucket_path_string.rs +++ /dev/null @@ -1,35 +0,0 @@ -use errors::anyhow; -use errors::AnyhowResult; - -use crate::util::hash_to_bucket_path::hash_to_bucket_path; - -#[deprecated(note = "this is a messy function and should be avoided")] -pub fn hash_to_bucket_path_string(file_hash: &str, - optional_root_directory: Option<&str>) - -> AnyhowResult -{ - let path = hash_to_bucket_path(file_hash, optional_root_directory)?; - - let maybe_path = path.to_str().map(|s| s.to_string()); - - maybe_path.ok_or(anyhow!("Path could not be converted")) -} - -#[cfg(test)] -mod tests { - use crate::util::hash_to_bucket_path_string::hash_to_bucket_path_string; - - #[test] - fn test_bucket_without_root() { - assert_eq!( - hash_to_bucket_path_string("abcdefg", None).unwrap(), - "/a/b/c/abcdefg".to_string()); - } - - #[test] - fn test_bucket_with_root() { - assert_eq!( - hash_to_bucket_path_string("abcdefg", Some("/root")).unwrap(), - "/root/a/b/c/abcdefg".to_string()); - } -} diff --git a/crates/_types/buckets/src/util/hashed_directory_path_short_string.rs b/crates/_types/buckets/src/util/hashed_directory_path_short_string.rs index c4fe2ca05a..e94410dc61 100644 --- a/crates/_types/buckets/src/util/hashed_directory_path_short_string.rs +++ b/crates/_types/buckets/src/util/hashed_directory_path_short_string.rs @@ -5,6 +5,7 @@ /// With a million items, each directory will have ~244 items. /// With a billion items, each directory will have ~244,140 items (impractical at this scale). /// +#[deprecated(note = "Use hashed_directory_path_long_string instead! (This function is only used by BucketPathUnifier, which should also die)")] pub fn hashed_directory_path_short_string(file_hash: &str) -> String { match file_hash.len() { 0 | 1 => "".to_string(), diff --git a/crates/_types/buckets/src/util/mod.rs b/crates/_types/buckets/src/util/mod.rs index ed783efb2c..095ae03a54 100644 --- a/crates/_types/buckets/src/util/mod.rs +++ b/crates/_types/buckets/src/util/mod.rs @@ -1,4 +1,2 @@ -pub (crate) mod hash_to_bucket_path; -pub mod hash_to_bucket_path_string; pub mod hashed_directory_path_long_string; pub mod hashed_directory_path_short_string; diff --git a/crates/lib/migration/src/voice_conversion/query_vc_model_for_migration.rs b/crates/lib/migration/src/voice_conversion/query_vc_model_for_migration.rs index c0db4adf8e..f3fa9042e1 100644 --- a/crates/lib/migration/src/voice_conversion/query_vc_model_for_migration.rs +++ b/crates/lib/migration/src/voice_conversion/query_vc_model_for_migration.rs @@ -361,7 +361,7 @@ mod tests { model.weights_type = WeightsType::RvcV2; model.has_index_file = true; let path = VcModel::ModelWeight(model).get_index_file_cloud_bucket_path(&BucketPathUnifier::default_paths()); - assert_eq!(path, Some(PathBuf::from("/weights/h/a/s/hash/hash.rvc_index"))); + assert_eq!(path, Some(PathBuf::from("/weights/h/a/s/hash/rvc_hash.index"))); } } } \ No newline at end of file diff --git a/crates/service/job/w2l_download_job/src/main.rs b/crates/service/job/w2l_download_job/src/main.rs index 324f2337c5..eab6cdcbe8 100644 --- a/crates/service/job/w2l_download_job/src/main.rs +++ b/crates/service/job/w2l_download_job/src/main.rs @@ -28,7 +28,6 @@ use sqlx::mysql::MySqlPoolOptions; use sqlx::MySqlPool; use tempdir::TempDir; -use buckets::util::hash_to_bucket_path_string::hash_to_bucket_path_string; use cloud_storage::bucket_client::BucketClient; use config::common_env::CommonEnv; use config::is_bad_video_download_url::is_bad_video_download_url; @@ -474,9 +473,11 @@ async fn process_job(downloader: &Downloader, job: &W2lTemplateUploadJobRecord) info!("File hash: {}", private_bucket_hash); // Full path to video/image - let full_object_path = hash_to_bucket_path_string( - &private_bucket_hash, - Some(&downloader.bucket_root_w2l_template_uploads))?; + //let full_object_path = hash_to_bucket_path_string( + // &private_bucket_hash, + // Some(&downloader.bucket_root_w2l_template_uploads))?; + + let full_object_path = "THIS_IS_BROKEN_BECAUSE_W2L_IS_DEAD"; // ==================== GENERATE VIDEO PREVIEWS ==================== // diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/w2l/enqueue_infer_w2l_with_uploads.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/w2l/enqueue_infer_w2l_with_uploads.rs index 8eea038050..0861c2d8f3 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/w2l/enqueue_infer_w2l_with_uploads.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/w2l/enqueue_infer_w2l_with_uploads.rs @@ -14,7 +14,6 @@ use futures::TryStreamExt; use log::{error, info, warn}; use r2d2_redis::redis::Commands; -use buckets::util::hash_to_bucket_path_string::hash_to_bucket_path_string; use container_common::token::random_uuid::generate_random_uuid; use enums::common::visibility::Visibility; use http_server_common::request::get_request_ip::get_request_ip; @@ -252,13 +251,15 @@ pub async fn enqueue_infer_w2l_with_uploads( let audio_upload_bucket_hash = upload_uuid.clone(); - let audio_upload_bucket_path = hash_to_bucket_path_string( - &upload_uuid, - Some(&server_state.audio_uploads_bucket_root) - ).map_err(|e| { - warn!("Hash bucket path error: {:?}", e); - InferW2lWithUploadError::ServerError - })?; + //let audio_upload_bucket_path = hash_to_bucket_path_string( + // &upload_uuid, + // Some(&server_state.audio_uploads_bucket_root) + //).map_err(|e| { + // warn!("Hash bucket path error: {:?}", e); + // InferW2lWithUploadError::ServerError + //})?; + + let audio_upload_bucket_path = "THIS_IS_BROKEN_BECAUSE_W2L_IS_DEAD"; info!("Uploading audio to bucket..."); server_state.private_bucket_client.upload_file_with_content_type( From 922e76eeb11a09535e910da57a332e39a9df1605 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Tue, 19 Dec 2023 21:53:04 -0500 Subject: [PATCH 091/124] migration fix wip --- .../copy_cloud_files.rs | 4 +- .../voice_conversion_to_weights/migrate.rs | 60 +++++++++++++++++-- ...odel_weight_from_voice_conversion_model.rs | 9 ++- 3 files changed, 61 insertions(+), 12 deletions(-) diff --git a/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/copy_cloud_files.rs b/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/copy_cloud_files.rs index 83d9c16f42..9d5f3468de 100644 --- a/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/copy_cloud_files.rs +++ b/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/copy_cloud_files.rs @@ -43,7 +43,7 @@ async fn copy_model(model: &WholeVoiceConversionModelRecord, deps: &Deps) -> Any VoiceConversionModelType::SoftVc => return Err(anyhow!("we never built softvc models")), }; - deps.bucket_development_public.upload_filename_with_content_type( + deps.bucket_production_public.upload_filename_with_content_type( &new_model_bucket_path.get_full_object_path_str(), &model_temp_fs_path, "application/octet-stream").await?; @@ -68,7 +68,7 @@ async fn copy_index_file(model: &WholeVoiceConversionModelRecord, deps: &Deps, b let new_model_bucket_path = WeightFileBucketPath::rvc_index_file_from_object_hash(bucket_path.get_object_hash()); - deps.bucket_development_public.upload_filename_with_content_type( + deps.bucket_production_public.upload_filename_with_content_type( &new_model_bucket_path.get_full_object_path_str(), &model_temp_fs_path, "application/octet-stream").await?; diff --git a/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/migrate.rs b/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/migrate.rs index 869808a36e..4263697209 100644 --- a/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/migrate.rs +++ b/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/migrate.rs @@ -1,9 +1,15 @@ use std::thread; use std::time::Duration; +use log::{info, warn}; + +use buckets::public::weight_files::bucket_file_path::WeightFileBucketPath; +use enums::by_table::model_weights::weights_types::WeightsType; use errors::AnyhowResult; -use mysql_queries::queries::model_weights::migration::upsert_model_weight_from_voice_conversion_model::upsert_model_weight_from_voice_conversion_model; -use mysql_queries::queries::voice_conversion::migration::list_whole_voice_conversion_models_using_cursor::list_whole_voice_conversion_models_using_cursor; +use mysql_queries::queries::model_weights::get_weight::get_weight_by_token; +use mysql_queries::queries::model_weights::migration::upsert_model_weight_from_voice_conversion_model::{CopiedFileData, upsert_model_weight_from_voice_conversion_model}; +use mysql_queries::queries::voice_conversion::migration::list_whole_voice_conversion_models_using_cursor::{list_whole_voice_conversion_models_using_cursor, WholeVoiceConversionModelRecord}; +use tokens::tokens::model_weights::ModelWeightToken; use crate::deps::Deps; use crate::migrations::voice_conversion_to_weights::copy_cloud_files::copy_cloud_files; @@ -15,17 +21,19 @@ pub async fn migrate_voice_conversion_to_weights(deps: &Deps) -> AnyhowResult<() let mut cursor = 0; loop { + info!("Querying {PAGE_SIZE} models at cursor = {cursor}"); + let results = list_whole_voice_conversion_models_using_cursor(&deps.mysql_production, PAGE_SIZE, cursor).await?; if results.is_empty() { + warn!("No more results found; exiting."); break; } for result in results.iter() { - println!("result: {:?}\n\n", result); - let copied_data = copy_cloud_files(result, &deps).await?; - upsert_model_weight_from_voice_conversion_model(result, &deps.mysql_development, &copied_data).await?; + println!("\n\nmigrating over result {:?} : {:?} ...", result.token, result); + copy_model_record_and_bucket_files(result, &deps).await?; } if let Some(last_id) = results.last().map(|result| result.id) { @@ -37,3 +45,45 @@ pub async fn migrate_voice_conversion_to_weights(deps: &Deps) -> AnyhowResult<() Ok(()) } + +async fn copy_model_record_and_bucket_files(record: &WholeVoiceConversionModelRecord, deps: &Deps) -> AnyhowResult<()> { + let mut maybe_copied_data = None; + + match &record.maybe_migration_new_model_weights_token { + None => { + info!("Copying bucket files for record {:?} ...", record.token); + let result = copy_cloud_files(record, &deps).await?; + maybe_copied_data = Some(result); + } + Some(token) => { + info!("Existing migrated record; skipping cloud bucket copy..."); + maybe_copied_data = lookup_bucket_details_from_record(token, &deps).await?; + } + } + + upsert_model_weight_from_voice_conversion_model(record, &deps.mysql_production, maybe_copied_data.as_ref()).await?; + + Ok(()) +} + +/// Look up the bucket storage details from a previously-migrated record +async fn lookup_bucket_details_from_record(model_weight_token: &ModelWeightToken, deps: &Deps) -> AnyhowResult> { + let maybe_model_weight_record = + get_weight_by_token(model_weight_token, true, &deps.mysql_production).await?; + + let model_weight_record = match maybe_model_weight_record { + None => return Ok(None), + Some(record) => record, + }; + + let bucket_path = match model_weight_record.weights_type { + WeightsType::RvcV2 => WeightFileBucketPath::rvc_model_file_from_object_hash(&model_weight_record.private_bucket_hash), + WeightsType::SoVitsSvc => WeightFileBucketPath::svc_model_file_from_object_hash(&model_weight_record.private_bucket_hash), + _ => return Ok(None), // NB: Stable Diffusion, etc. aren't valid for migration + }; + + Ok(Some(CopiedFileData { + bucket_path, + file_sha_hash: model_weight_record.file_checksum_sha2, + })) +} \ No newline at end of file diff --git a/crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs b/crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs index 5c480ce813..bbcc71323e 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs @@ -22,18 +22,17 @@ pub struct CopiedFileData { pub async fn upsert_model_weight_from_voice_conversion_model( record: &WholeVoiceConversionModelRecord, mysql_pool: &MySqlPool, - copied_data: &CopiedFileData, + maybe_copied_data: Option<&CopiedFileData>, ) -> AnyhowResult<()> { let mut transaction = mysql_pool.begin().await?; let model_weight_token = create_or_generate_token(record); - upsert_model_weights_record(record, &model_weight_token, copied_data, &mut transaction).await?; + upsert_model_weights_record(record, &model_weight_token, maybe_copied_data, &mut transaction).await?; upsert_model_weights_extension_record(record, &model_weight_token, &mut transaction).await?; - // TODO: Don't update source record with new token *unless* we're backfilling the same database. - // update_original_record(record, &model_weight_token, &mut transaction).await?; + update_original_record(record, &model_weight_token, &mut transaction).await?; transaction.commit().await?; @@ -50,7 +49,7 @@ pub fn create_or_generate_token(record: &WholeVoiceConversionModelRecord) -> Mod pub async fn upsert_model_weights_record( record: &WholeVoiceConversionModelRecord, model_weight_token: &ModelWeightToken, - copied_data: &CopiedFileData, + maybe_copied_data: Option<&CopiedFileData>, mut transaction: &mut Transaction<'_, MySql>, ) -> AnyhowResult<()> { From 44d75baeec4bbaee2bb0d770ef27911755c0a252 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Tue, 19 Dec 2023 22:26:04 -0500 Subject: [PATCH 092/124] update old record with token --- Cargo.lock | 1 + crates/cli/migration-tool/Cargo.toml | 1 + .../copy_cloud_files.rs | 8 ++++++++ .../voice_conversion_to_weights/migrate.rs | 5 ++++- ...model_weight_from_voice_conversion_model.rs | 18 +++++++++++++++--- 5 files changed, 29 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 840d827860..4fd0695c9c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3519,6 +3519,7 @@ dependencies = [ "easyenv", "enums", "errors", + "filesys", "hashing", "log", "my-workspace-hack", diff --git a/crates/cli/migration-tool/Cargo.toml b/crates/cli/migration-tool/Cargo.toml index 26e243858e..bf2cc11e90 100644 --- a/crates/cli/migration-tool/Cargo.toml +++ b/crates/cli/migration-tool/Cargo.toml @@ -20,6 +20,7 @@ config = { path = "../../lib/deprecated/config" } easyenv = { path = "../../lib/easyenv" } enums = { path = "../../_types/enums" } errors = { path = "../../lib/errors" } +filesys = { path = "../../lib/files/filesys" } hashing = { path = "../../lib/files/hashing" } mysql_queries = { path = "../../lib/mysql_queries" } storyteller_root = { path = "../../lib/storyteller_root" } diff --git a/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/copy_cloud_files.rs b/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/copy_cloud_files.rs index 9d5f3468de..ebc35303ce 100644 --- a/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/copy_cloud_files.rs +++ b/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/copy_cloud_files.rs @@ -4,6 +4,8 @@ use buckets::public::weight_files::bucket_file_path::WeightFileBucketPath; use cloud_storage::bucket_path_unifier::BucketPathUnifier; use enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType; use errors::{anyhow, AnyhowResult}; +use filesys::safe_delete_temp_directory::safe_delete_temp_directory; +use filesys::safe_delete_temp_file::safe_delete_temp_file; use hashing::sha256::sha256_hash_file::sha256_hash_file; use mysql_queries::queries::model_weights::migration::upsert_model_weight_from_voice_conversion_model::CopiedFileData; use mysql_queries::queries::voice_conversion::migration::list_whole_voice_conversion_models_using_cursor::WholeVoiceConversionModelRecord; @@ -48,6 +50,9 @@ async fn copy_model(model: &WholeVoiceConversionModelRecord, deps: &Deps) -> Any &model_temp_fs_path, "application/octet-stream").await?; + safe_delete_temp_file(&model_temp_fs_path); + safe_delete_temp_directory(&temp_dir); + Ok(CopiedFileData { bucket_path: new_model_bucket_path, file_sha_hash: file_checksum, @@ -73,5 +78,8 @@ async fn copy_index_file(model: &WholeVoiceConversionModelRecord, deps: &Deps, b &model_temp_fs_path, "application/octet-stream").await?; + safe_delete_temp_file(&model_temp_fs_path); + safe_delete_temp_directory(&temp_dir); + Ok(()) // NB: We don't care about the path of the index file. } diff --git a/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/migrate.rs b/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/migrate.rs index 4263697209..6c9beacc14 100644 --- a/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/migrate.rs +++ b/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/migrate.rs @@ -61,7 +61,10 @@ async fn copy_model_record_and_bucket_files(record: &WholeVoiceConversionModelRe } } - upsert_model_weight_from_voice_conversion_model(record, &deps.mysql_production, maybe_copied_data.as_ref()).await?; + if let Some(copied_data) = &maybe_copied_data { + info!("Upserting records..."); + upsert_model_weight_from_voice_conversion_model(record, &deps.mysql_production, copied_data).await?; + } Ok(()) } diff --git a/crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs b/crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs index bbcc71323e..76799a629c 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs @@ -22,14 +22,14 @@ pub struct CopiedFileData { pub async fn upsert_model_weight_from_voice_conversion_model( record: &WholeVoiceConversionModelRecord, mysql_pool: &MySqlPool, - maybe_copied_data: Option<&CopiedFileData>, + copied_data: &CopiedFileData, ) -> AnyhowResult<()> { let mut transaction = mysql_pool.begin().await?; let model_weight_token = create_or_generate_token(record); - upsert_model_weights_record(record, &model_weight_token, maybe_copied_data, &mut transaction).await?; + upsert_model_weights_record(record, &model_weight_token, copied_data, &mut transaction).await?; upsert_model_weights_extension_record(record, &model_weight_token, &mut transaction).await?; update_original_record(record, &model_weight_token, &mut transaction).await?; @@ -49,7 +49,7 @@ pub fn create_or_generate_token(record: &WholeVoiceConversionModelRecord) -> Mod pub async fn upsert_model_weights_record( record: &WholeVoiceConversionModelRecord, model_weight_token: &ModelWeightToken, - maybe_copied_data: Option<&CopiedFileData>, + copied_data: &CopiedFileData, mut transaction: &mut Transaction<'_, MySql>, ) -> AnyhowResult<()> { @@ -226,6 +226,18 @@ pub async fn update_original_record( model_weight_token: &ModelWeightToken, transaction: &mut Transaction<'_, MySql> ) -> AnyhowResult<()> { + let query = sqlx::query!( + r#" +UPDATE voice_conversion_models +SET + maybe_migration_new_model_weights_token = ? +WHERE token = ? + "#, + model_weight_token, + record.token, + ); + + let _r = query.execute(&mut **transaction).await?; Ok(()) } From a2aa71e8a6a7bfee824fb5ef242d4b475e2e4a90 Mon Sep 17 00:00:00 2001 From: Michael Chung Date: Tue, 19 Dec 2023 23:25:18 -0500 Subject: [PATCH 093/124] builds properly now working on the download aspect. --- Cargo.lock | 9 +- crates/_types/buckets/Cargo.toml | 7 -- crates/_types/buckets/src/public/mod.rs | 1 - .../src/seeding/seed_media_files.rs | 2 + .../lib/api_clients/cloud_storage/Cargo.toml | 6 + .../cloud_storage/src/bucket_client.rs | 36 +++++- .../remote_file_manager/file_descriptor.rs | 77 +------------ .../src/remote_file_manager/file_directory.rs | 66 +++++++++++ .../src/remote_file_manager/mod.rs | 4 +- .../remote_cloud_file_manager.rs | 105 ++++++++++++------ 10 files changed, 192 insertions(+), 121 deletions(-) create mode 100644 crates/lib/api_clients/cloud_storage/src/remote_file_manager/file_directory.rs diff --git a/Cargo.lock b/Cargo.lock index e3511bf717..1e791d92eb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -912,9 +912,6 @@ version = "0.0.1" dependencies = [ "crockford", "errors", - "filesys", - "hashing", - "mimetypes", "my-workspace-hack", ] @@ -1128,7 +1125,13 @@ version = "0.0.1" dependencies = [ "anyhow", "buckets", + "crockford", + "easyenv", + "errors", + "filesys", + "hashing", "log", + "mimetypes", "my-workspace-hack", "rust-s3", "tokio", diff --git a/crates/_types/buckets/Cargo.toml b/crates/_types/buckets/Cargo.toml index 218cd6be37..75e4b6e2be 100644 --- a/crates/_types/buckets/Cargo.toml +++ b/crates/_types/buckets/Cargo.toml @@ -18,13 +18,6 @@ path = "src/lib.rs" crockford = { path = "../../lib/crockford" } errors = { path = "../../lib/errors" } -# probably need to have it's own module. -filesys = { path = "../../lib/files/filesys" } -hashing = { path = "../../lib/files/hashing" } -mimetypes = { path = "../../lib/files/mimetypes" } -# have to add this to it's own module..... -# buckets = { path = "../../_types/buckets" } -# cloud_storage = { path = "../../lib/api_clients/cloud_storage" } # Workspace hack (faster compile times) my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" } diff --git a/crates/_types/buckets/src/public/mod.rs b/crates/_types/buckets/src/public/mod.rs index c357e13f4a..a0a03b9ad8 100644 --- a/crates/_types/buckets/src/public/mod.rs +++ b/crates/_types/buckets/src/public/mod.rs @@ -4,4 +4,3 @@ pub mod public_path; pub mod voice_conversion_results; pub mod weight_uploads; pub mod weight_files; -pub mod files; diff --git a/crates/cli/dev-database-seed/src/seeding/seed_media_files.rs b/crates/cli/dev-database-seed/src/seeding/seed_media_files.rs index 8036018f83..34956f17cd 100644 --- a/crates/cli/dev-database-seed/src/seeding/seed_media_files.rs +++ b/crates/cli/dev-database-seed/src/seeding/seed_media_files.rs @@ -5,8 +5,10 @@ use sqlx::{MySql, Pool}; use buckets::public::media_files::bucket_file_path::MediaFileBucketPath; use enums::by_table::media_files::media_file_type::MediaFileType; + use enums::common::visibility::Visibility; use errors::AnyhowResult; + use filesys::file_read_bytes::file_read_bytes; use filesys::file_size::file_size; use filesys::path_to_string::path_to_string; diff --git a/crates/lib/api_clients/cloud_storage/Cargo.toml b/crates/lib/api_clients/cloud_storage/Cargo.toml index 2cd5d20198..150adaaf58 100644 --- a/crates/lib/api_clients/cloud_storage/Cargo.toml +++ b/crates/lib/api_clients/cloud_storage/Cargo.toml @@ -16,6 +16,12 @@ path = "src/lib.rs" # Internal buckets = { path = "../../../_types/buckets" } +crockford = { path = "../../../lib/crockford" } +errors = { path = "../../../lib/errors" } +easyenv = { path = "../../../lib/easyenv" } +filesys = { path = "../../../lib/files/filesys" } +hashing = { path = "../../../lib/files/hashing" } +mimetypes = { path = "../../../lib/files/mimetypes" } # Workspace hack (faster compile times) my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" } diff --git a/crates/lib/api_clients/cloud_storage/src/bucket_client.rs b/crates/lib/api_clients/cloud_storage/src/bucket_client.rs index 677507c110..a1b1e28dd8 100644 --- a/crates/lib/api_clients/cloud_storage/src/bucket_client.rs +++ b/crates/lib/api_clients/cloud_storage/src/bucket_client.rs @@ -14,11 +14,26 @@ use tokio::io::AsyncReadExt; #[derive(Clone)] pub struct BucketClient { bucket: Bucket, - /// If set, put all files under this root path. optional_bucket_root: Option, } + +#[derive(Debug)] +pub enum BucketClientError { + ErrorWithCodeAndMessage { code: u16, message: String }, +} + +impl std::fmt::Display for BucketClientError { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + BucketClientError::ErrorWithCodeAndMessage { code, message } => write!(f, "Error {}: {}", code, message), + } + } +} +impl std::error::Error for BucketClientError {} + + impl BucketClient { pub fn create( @@ -87,6 +102,25 @@ impl BucketClient { Ok(()) } + pub async fn upload_file_with_content_type_process(&self, object_name: &str, bytes: &[u8], content_type: &str) -> anyhow::AnyhowResult<()> { + info!("Filename for bucket: {}", object_name); + let object_name = self.get_rooted_object_name(object_name); + info!("Rooted filename for bucket: {}", object_name); + let response = self.bucket.put_object_with_content_type(&object_name, bytes, content_type).await?; + let body_bytes = response.bytes(); + let code = response.status_code(); + info!("upload code: {}", code); + if code != 200 { + let body = String::from_utf8_lossy(body_bytes); + warn!("upload body: {}", body); + BucketClientError::ErrorWithCodeAndMessage { code, message: body.to_string() }; + } else { + info!("upload success: {}", code); + Ok(()) + } + } + + #[deprecated = "Use upload_file instead above it returns an error we can surface and act on."] pub async fn upload_file_with_content_type(&self, object_name: &str, bytes: &[u8], content_type: &str) -> anyhow::Result<()> { info!("Filename for bucket: {}", object_name); diff --git a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/file_descriptor.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/file_descriptor.rs index b9b186a4d2..4f26dd6bf8 100644 --- a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/file_descriptor.rs +++ b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/file_descriptor.rs @@ -1,9 +1,8 @@ // Describes the file and how it will be saved to GCBucket // where the file should be stored based off the descriptor - use std::path::PathBuf; use crockford::crockford_entropy_lower; -use crate::util::hashed_directory_path_long_string; +use buckets::util::hashed_directory_path_long_string; // DEFAULT IMPLEMENTATION const REMOTE_FILE_DIRECTORY: &str = "/implement_google_cloud_storage_bucket_name"; @@ -31,76 +30,6 @@ pub trait FileDescriptor { } } -pub struct FileBucketDirectory { - file_object_hash: String, - cloud_directory_hash: String, - remote_cloud_base_directory: String, - full_remote_cloud_file_path: String, - file_name: String, - file_descriptor: Box -} - -impl FileBucketDirectory { - pub fn generate_new(file_descriptor: Box) -> Self { - Self::from_object_hash(file_descriptor) - } - - fn from_object_hash(file_descriptor: Box) -> Self { - let cloud_path_entropy = crockford_entropy_lower(32); - let file_name_entropy = crockford_entropy_lower(32); - - // gets you wiki /a/b/c/d folder structure - let middle = hashed_directory_path_long_string::hashed_directory_path_long_string(cloud_path_entropy.as_ref()); - - // gets you cloud bucket path e.g weights/a/b/c/d/clould_path_entropy - let remote_cloud_base_directory = format!("{}/{}{}", file_descriptor.remote_directory_path(), middle, cloud_path_entropy); - - // gets you name of the file with suffix and prefix and entropy in the centre - let file_name = format!("{}_{}.{}", file_descriptor.get_prefix(), file_name_entropy, file_descriptor.get_suffix()); - // note: no longer optional because it's easy to know what it would be in the db explicit is better than implcit. - - // This is the full path you upload to. - let full_remote_cloud_file_path = format!("{}/{}", remote_cloud_base_directory , file_name); - Self { - file_object_hash: file_name_entropy, - cloud_directory_hash: cloud_path_entropy, - remote_cloud_base_directory: remote_cloud_base_directory, - full_remote_cloud_file_path: full_remote_cloud_file_path, - file_name:file_name, - file_descriptor:file_descriptor - } - } - - pub fn get_file_object_hash(&self) -> &str { - &self.file_object_hash - } - - pub fn get_cloud_directory_hash(&self) -> &str { - &self.cloud_directory_hash - } - - pub fn get_remote_cloud_base_directory(&self) -> &str { - &self.remote_cloud_base_directory - } - - pub fn get_full_remote_cloud_file_path(&self) -> &str { - &self.full_remote_cloud_file_path - } - - pub fn to_full_remote_cloud_file_path_pathbuf(&self) -> PathBuf { - PathBuf::from(&self.full_remote_cloud_file_path) - } - - pub fn get_file_name(&self) -> &str { - &self.file_name - } - - // pub fn get_file_descriptor(&self) -> Box { - // self.file_descriptor - // } - -} - #[cfg(test)] mod tests { @@ -108,8 +37,8 @@ mod tests { pub fn test() {} pub fn generate_new_entropy() { - let directory = FileDescriptorBucketDirectory::generate_new(); - assert_eq!(directory.get_object_hash().len(), 32); + // let directory = FileDescriptorBucketDirectory::generate_new(); + // assert_eq!(directory.get_object_hash().len(), 32); } // #[test] diff --git a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/file_directory.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/file_directory.rs new file mode 100644 index 0000000000..4bb30ac005 --- /dev/null +++ b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/file_directory.rs @@ -0,0 +1,66 @@ + +use std::path::PathBuf; +use crockford::crockford_entropy_lower; +use buckets::util::hashed_directory_path_long_string; +use crate::remote_file_manager::file_descriptor::FileDescriptor; + +pub struct FileBucketDirectory { + file_object_hash: String, + remote_cloud_base_directory: String, + full_remote_cloud_file_path: String, + file_name: String, + file_descriptor: Box + } + + impl FileBucketDirectory { + pub fn generate_new(file_descriptor: Box) -> Self { + Self::from_object_hash(file_descriptor) + } + + fn from_object_hash(file_descriptor: Box) -> Self { + let entropy = crockford_entropy_lower(32); + // gets you wiki /a/b/c/d folder structure + let middle = hashed_directory_path_long_string::hashed_directory_path_long_string(entropy.as_ref()); + // gets you cloud bucket path e.g weights/a/b/c/d/clould_path_entropy + let remote_cloud_base_directory = format!("{}/{}{}", file_descriptor.remote_directory_path(), middle, entropy); + // gets you name of the file with suffix and prefix and entropy in the centre + let file_name = format!("{}_{}.{}", file_descriptor.get_prefix(), entropy, file_descriptor.get_suffix()); + // note: no longer optional because it's easy to know what it would be in the db explicit is better than implcit. + + // This is the full path you upload to. + let full_remote_cloud_file_path = format!("{}/{}", remote_cloud_base_directory , file_name); + Self { + file_object_hash: entropy, + remote_cloud_base_directory: remote_cloud_base_directory, + full_remote_cloud_file_path: full_remote_cloud_file_path, + file_name:file_name, + file_descriptor:file_descriptor + } + } + + pub fn get_file_object_hash(&self) -> &str { + &self.file_object_hash + } + + pub fn get_remote_cloud_base_directory(&self) -> &str { + &self.remote_cloud_base_directory + } + + pub fn get_full_remote_cloud_file_path(&self) -> &str { + &self.full_remote_cloud_file_path + } + + pub fn to_full_remote_cloud_file_path_pathbuf(&self) -> PathBuf { + PathBuf::from(&self.full_remote_cloud_file_path) + } + + pub fn get_file_name(&self) -> &str { + &self.file_name + } + + // pub fn get_file_descriptor(&self) -> Box { + // self.file_descriptor + // } + + } + \ No newline at end of file diff --git a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/mod.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/mod.rs index d818e2bc52..4bb18414b2 100644 --- a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/mod.rs +++ b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/mod.rs @@ -1,7 +1,7 @@ pub mod remote_cloud_file_manager; - +pub mod file_directory; pub mod file_meta_data; - pub mod file_descriptor; + pub mod media_descriptor; pub mod weights_descriptor; \ No newline at end of file diff --git a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_file_manager.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_file_manager.rs index 992968af46..41f95bf1f2 100644 --- a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_file_manager.rs +++ b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_file_manager.rs @@ -1,49 +1,94 @@ -use crate::public::files::file_descriptor::FileDescriptor; -use crate::public::files::file_meta_data::FileMetaData; +use crate::bucket_client::BucketClient; +use super::file_descriptor::FileDescriptor; +use super::file_meta_data::FileMetaData; -use super::file_descriptor::FileBucketDirectory; +use std::time::Duration; +use errors::{AnyhowError, AnyhowResult}; -use errors::AnyhowError; use filesys::file_read_bytes::file_read_bytes; use filesys::file_size::file_size; use filesys::path_to_string::path_to_string; use hashing::sha256::sha256_hash_file::sha256_hash_file; - use mimetypes::mimetype_for_bytes::get_mimetype_for_bytes; use mimetypes::mimetype_for_file::get_mimetype_for_file; +use s3::bucket; +use log::info; -struct WebFileManager { - // bucket_client: BucketClients, +// Takes the definition from database and is an input to enable us to download the file. +struct RemoteCloudBucketDetails { + bucket_hash: String, + // Might require a migration to add this field to the database? + maybe_bucket_prefix: Option, + maybe_bucket_extension: Option, +} + +struct RemoteCloudFileClient { + bucket_client: BucketClient, file_descriptor: Box } -impl WebFileManager { +impl RemoteCloudFileClient { // bucket_client:BucketClients - fn new(file_descriptor: Box) -> WebFileManager { - WebFileManager { - // bucket_client: bucket_client, - file_descriptor: file_descriptor - } + fn bucket_client_for_object(&self) -> &BucketClient { + &self.bucket_client } - - // also include bucket details here - pub fn download_file(&self, system_file_path:String) -> Result<(),AnyhowError> { + fn new(file_descriptor: Box) -> AnyhowResult { + // Please verify that this is the correct way to get the bucket clients public and private in production and dev? + let access_key = easyenv::get_env_string_required("ACCESS_KEY")?; + let secret_key = easyenv::get_env_string_required("SECRET_KEY")?; + let region_name = easyenv::get_env_string_required("REGION_NAME")?; - } - // return error or success with meta data. - pub fn upload_file(&self, system_file_path:String) -> Result { - // let bucket_client = self.bucket_client.clone(); - if self.file_descriptor.is_public() { - - }else { - // use private bucket client + let public_bucket_name = easyenv::get_env_string_required("PUBLIC_BUCKET_NAME")?; + let private_bucket_name = easyenv::get_env_string_required("PRIVATE_BUCKET_NAME")?; + // NB: Long timeout for dev rust builds to upload to cloud buckets. + // Unoptimized binaries sometimes take a lot of time to upload, presumably due to unoptimized code. + let bucket_timeout = easyenv::get_env_duration_seconds_or_default( + "BUCKET_TIMEOUT_SECONDS", Duration::from_secs(60 * 10)); + let mut bucket_client:BucketClient; + if file_descriptor.is_public() { + // use public bucket client + info!("Configuring public GCS bucket..."); + bucket_client = BucketClient::create( + &access_key, + &secret_key, + ®ion_name, + &public_bucket_name, + None, + Some(bucket_timeout), + )?; + } else { + // use private bucket client + info!("Configuring private GCS bucket..."); + bucket_client = BucketClient::create( + &access_key, + &secret_key, + ®ion_name, + &private_bucket_name, + None, + Some(bucket_timeout), + )?; } - let result = Self::get_file_meta_data(system_file_path.clone())?; - Ok(result) + + Ok(RemoteCloudFileClient { + bucket_client: bucket_client, + file_descriptor: file_descriptor + }) } + // // also include bucket details here + // pub async fn download_file(&self, remote_cloud_bucket_details:RemoteCloudBucketDetails, to_system_file_path:String) -> AnyHowResult<> { + // self.bucket_client.download_file_to_disk(object_path, filesystem_path) + // } + + // // return error or success with meta data. + // pub async fn upload_file(&self, from_system_file_path:String) -> Result { + // // get file meta data + // let result = Self::get_file_meta_data(system_file_path.clone())?; + // Ok(result) + // } + // Retrieve the metadata from the file pub fn get_file_meta_data(system_file_path:String) -> Result { let file_size_bytes = file_size(system_file_path.clone())?; @@ -60,16 +105,10 @@ impl WebFileManager { } } - -// take in system file path to upload. -// take in system file path to download to. - -// should be able to take prefix suffix and entrpy to generate a file descriptor - #[cfg(test)] mod tests { //use crate::public::files::file_descriptor::{FileDescriptor}; - //use super::WebFileManager; + //use super::RemoteCloudFileClient; #[test] fn test_web_file_manager() { println!("test") From ab3a31289818a20a25f4a60c5fda0e1edb3f39d6 Mon Sep 17 00:00:00 2001 From: Michael Chung Date: Wed, 20 Dec 2023 00:13:02 -0500 Subject: [PATCH 094/124] Ok so it actually compiles right now. --- .../lib/api_clients/cloud_storage/src/bucket_client.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/lib/api_clients/cloud_storage/src/bucket_client.rs b/crates/lib/api_clients/cloud_storage/src/bucket_client.rs index a1b1e28dd8..a71aece7a0 100644 --- a/crates/lib/api_clients/cloud_storage/src/bucket_client.rs +++ b/crates/lib/api_clients/cloud_storage/src/bucket_client.rs @@ -1,6 +1,6 @@ use std::path::Path; use std::time::Duration; - +use errors::AnyhowResult; use anyhow::anyhow; use anyhow::bail; use log::info; @@ -10,7 +10,7 @@ use s3::creds::Credentials; use s3::region::Region; use tokio::fs::File; use tokio::io::AsyncReadExt; - + use std::error::Error; #[derive(Clone)] pub struct BucketClient { bucket: Bucket, @@ -31,7 +31,7 @@ impl std::fmt::Display for BucketClientError { } } } -impl std::error::Error for BucketClientError {} +impl Error for BucketClientError {} impl BucketClient { @@ -102,7 +102,7 @@ impl BucketClient { Ok(()) } - pub async fn upload_file_with_content_type_process(&self, object_name: &str, bytes: &[u8], content_type: &str) -> anyhow::AnyhowResult<()> { + pub async fn upload_file_with_content_type_process(&self, object_name: &str, bytes: &[u8], content_type: &str) -> AnyhowResult<()> { info!("Filename for bucket: {}", object_name); let object_name = self.get_rooted_object_name(object_name); info!("Rooted filename for bucket: {}", object_name); @@ -113,7 +113,7 @@ impl BucketClient { if code != 200 { let body = String::from_utf8_lossy(body_bytes); warn!("upload body: {}", body); - BucketClientError::ErrorWithCodeAndMessage { code, message: body.to_string() }; + return Err(anyhow!("upload failed: {}", code)); } else { info!("upload success: {}", code); Ok(()) From 57f383612fb15709accfec95b89d33e135dab57c Mon Sep 17 00:00:00 2001 From: Michael Chung Date: Wed, 20 Dec 2023 02:20:44 -0500 Subject: [PATCH 095/124] Now testing time! --- .../cloud_storage/src/bucket_client.rs | 3 - .../remote_file_manager/file_descriptor.rs | 24 ---- .../src/remote_file_manager/file_directory.rs | 35 ++++-- .../remote_cloud_file_manager.rs | 117 ++++++++++++------ .../remote_file_manager/weights_descriptor.rs | 77 ++++++++++++ 5 files changed, 180 insertions(+), 76 deletions(-) diff --git a/crates/lib/api_clients/cloud_storage/src/bucket_client.rs b/crates/lib/api_clients/cloud_storage/src/bucket_client.rs index a71aece7a0..8c3f2a6ba4 100644 --- a/crates/lib/api_clients/cloud_storage/src/bucket_client.rs +++ b/crates/lib/api_clients/cloud_storage/src/bucket_client.rs @@ -226,7 +226,6 @@ impl BucketClient { object_path: P, filesystem_path: Q, ) -> anyhow::Result<()> { - // TODO I think we might want to return an error here? but there has to a reason why we are just returning ok? let object_path_str = object_path.as_ref() .to_str() .map(|s| s.to_string()) @@ -242,9 +241,7 @@ impl BucketClient { 404 => bail!("File not found in bucket: {}", &object_path_str), _ => {}, } - info!("download code: {}", status_code); - Ok(()) } diff --git a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/file_descriptor.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/file_descriptor.rs index 4f26dd6bf8..e265091162 100644 --- a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/file_descriptor.rs +++ b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/file_descriptor.rs @@ -35,28 +35,4 @@ mod tests { #[test] pub fn test() {} - - pub fn generate_new_entropy() { - // let directory = FileDescriptorBucketDirectory::generate_new(); - // assert_eq!(directory.get_object_hash().len(), 32); - } - - // #[test] - // pub fn get_directory_path_str() { - // let directory = FileDescriptorBucketDirectory::from_object_hash("abcdefghijk"); - // assert_eq!(directory.get_directory_path_str(), format!("/{}/a/b/c/d/e/abcdefghijk",REMOTE_FILE_DIRECTORY)); - // } - - // #[test] - // pub fn get_directory_path_str_short_name() { - // let directory = FileDescriptorBucketDirectory::from_object_hash("foo"); - // assert_eq!(directory.get_directory_path_str(), format!("/{}/f/o/foo",REMOTE_FILE_DIRECTORY)); - // } - - // #[test] - // pub fn get_object_hash() { - // let hash = "abcdefghijk"; - // let directory = FileDescriptorBucketDirectory::from_object_hash(hash); - // assert_eq!(directory.get_object_hash(), hash); - // } } \ No newline at end of file diff --git a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/file_directory.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/file_directory.rs index 4bb30ac005..c55863670f 100644 --- a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/file_directory.rs +++ b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/file_directory.rs @@ -3,7 +3,7 @@ use std::path::PathBuf; use crockford::crockford_entropy_lower; use buckets::util::hashed_directory_path_long_string; use crate::remote_file_manager::file_descriptor::FileDescriptor; - +use crate::remote_file_manager::remote_cloud_file_manager::RemoteCloudBucketDetails; pub struct FileBucketDirectory { file_object_hash: String, remote_cloud_base_directory: String, @@ -14,10 +14,31 @@ pub struct FileBucketDirectory { impl FileBucketDirectory { pub fn generate_new(file_descriptor: Box) -> Self { - Self::from_object_hash(file_descriptor) + Self::new_from_file_descriptor(file_descriptor) } - - fn from_object_hash(file_descriptor: Box) -> Self { + + // TODO refactor this out of here + pub fn from_existing_bucket_details(bucket_details:RemoteCloudBucketDetails) -> Self { + let file_descriptor = bucket_details.file_descriptor_from_bucket_details(); + let entropy = bucket_details.get_object_hash(); + let middle = hashed_directory_path_long_string::hashed_directory_path_long_string(entropy.as_ref()); + // gets you cloud bucket path e.g weights/a/b/c/d/clould_path_entropy + let remote_cloud_base_directory = format!("{}/{}{}", file_descriptor.remote_directory_path(), middle, entropy); + // gets you name of the file with suffix and prefix and entropy in the centre + let file_name = format!("{}_{}.{}", bucket_details.get_prefix(), entropy, bucket_details.get_suffix()); + // note: no longer optional because it's easy to know what it would be in the db explicit is better than implcit. + // This is the full path you download from + let full_remote_cloud_file_path = format!("{}/{}", remote_cloud_base_directory , file_name); + Self { + file_object_hash: entropy.to_string(), + remote_cloud_base_directory: remote_cloud_base_directory, + full_remote_cloud_file_path: full_remote_cloud_file_path, + file_name:file_name, + file_descriptor:file_descriptor + } + } + + pub fn new_from_file_descriptor(file_descriptor: Box) -> Self { let entropy = crockford_entropy_lower(32); // gets you wiki /a/b/c/d folder structure let middle = hashed_directory_path_long_string::hashed_directory_path_long_string(entropy.as_ref()); @@ -57,10 +78,6 @@ pub struct FileBucketDirectory { pub fn get_file_name(&self) -> &str { &self.file_name } - - // pub fn get_file_descriptor(&self) -> Box { - // self.file_descriptor - // } - + } \ No newline at end of file diff --git a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_file_manager.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_file_manager.rs index 41f95bf1f2..58255adefa 100644 --- a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_file_manager.rs +++ b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_file_manager.rs @@ -1,9 +1,11 @@ use crate::bucket_client::BucketClient; -use super::file_descriptor::FileDescriptor; +use crate::remote_file_manager::file_directory::FileBucketDirectory; +use super::file_descriptor::{FileDescriptor, self}; use super::file_meta_data::FileMetaData; use std::time::Duration; +use anyhow::Ok; use errors::{AnyhowError, AnyhowResult}; use filesys::file_read_bytes::file_read_bytes; @@ -11,43 +13,71 @@ use filesys::file_size::file_size; use filesys::path_to_string::path_to_string; use hashing::sha256::sha256_hash_file::sha256_hash_file; use mimetypes::mimetype_for_bytes::get_mimetype_for_bytes; -use mimetypes::mimetype_for_file::get_mimetype_for_file; +use mimetypes::mimetype_for_file::{get_mimetype_for_file, self}; use s3::bucket; use log::info; +use super::weights_descriptor::{WeightsLoRADescriptor, WeightsSD15Descriptor, WeightsSDXLDescriptor, self}; + // Takes the definition from database and is an input to enable us to download the file. -struct RemoteCloudBucketDetails { - bucket_hash: String, - // Might require a migration to add this field to the database? - maybe_bucket_prefix: Option, - maybe_bucket_extension: Option, +pub struct RemoteCloudBucketDetails { + object_hash: String, + prefix: String, + suffix: String, } -struct RemoteCloudFileClient { - bucket_client: BucketClient, - file_descriptor: Box -} - -impl RemoteCloudFileClient { - // bucket_client:BucketClients - fn bucket_client_for_object(&self) -> &BucketClient { - &self.bucket_client +impl RemoteCloudBucketDetails { + pub fn new(object_hash: String, prefix: String, suffix: String) -> Self { + Self { + object_hash: object_hash, + prefix: prefix, + suffix: suffix + } + } + pub fn get_object_hash(&self) -> &str { + &self.object_hash + } + pub fn get_prefix(&self) -> &str { + &self.prefix + } + pub fn get_suffix(&self) -> &str { + &self.suffix } - fn new(file_descriptor: Box) -> AnyhowResult { - // Please verify that this is the correct way to get the bucket clients public and private in production and dev? + pub fn file_descriptor_from_bucket_details(&self) -> Box { + match self.prefix.as_str() { + "loRA" => Box::new(weights_descriptor::WeightsLoRADescriptor {}), + "SD15" => Box::new(weights_descriptor::WeightsSD15Descriptor {}), + "SDXL" => Box::new(weights_descriptor::WeightsSDXLDescriptor {}), + _ => panic!("Unknown prefix: {}", self.prefix) + } + } +} + +struct RemoteCloudFileClient {} + +impl RemoteCloudFileClient { + + pub async fn download_file(&self, remote_cloud_bucket_details:RemoteCloudBucketDetails, to_system_file_path:String) -> AnyhowResult<()> { + let file_descriptor = remote_cloud_bucket_details.file_descriptor_from_bucket_details(); + let file_bucket_directory = FileBucketDirectory::from_existing_bucket_details(remote_cloud_bucket_details); + let full_remote_cloud_file_path = file_bucket_directory.get_full_remote_cloud_file_path(); + let bucket_client = self.get_bucket_with_visbility(file_descriptor.is_public()).await?; + bucket_client.download_file_to_disk(full_remote_cloud_file_path, to_system_file_path); + Ok(()) + } + + pub async fn get_bucket_with_visbility(&self, public:bool) -> Result { let access_key = easyenv::get_env_string_required("ACCESS_KEY")?; let secret_key = easyenv::get_env_string_required("SECRET_KEY")?; let region_name = easyenv::get_env_string_required("REGION_NAME")?; - let public_bucket_name = easyenv::get_env_string_required("PUBLIC_BUCKET_NAME")?; let private_bucket_name = easyenv::get_env_string_required("PRIVATE_BUCKET_NAME")?; - // NB: Long timeout for dev rust builds to upload to cloud buckets. - // Unoptimized binaries sometimes take a lot of time to upload, presumably due to unoptimized code. + let bucket_timeout = easyenv::get_env_duration_seconds_or_default( "BUCKET_TIMEOUT_SECONDS", Duration::from_secs(60 * 10)); let mut bucket_client:BucketClient; - if file_descriptor.is_public() { + if public { // use public bucket client info!("Configuring public GCS bucket..."); bucket_client = BucketClient::create( @@ -59,7 +89,6 @@ impl RemoteCloudFileClient { Some(bucket_timeout), )?; } else { - // use private bucket client info!("Configuring private GCS bucket..."); bucket_client = BucketClient::create( &access_key, @@ -70,27 +99,35 @@ impl RemoteCloudFileClient { Some(bucket_timeout), )?; } - - Ok(RemoteCloudFileClient { - bucket_client: bucket_client, - file_descriptor: file_descriptor - }) + Ok(bucket_client) } - // // also include bucket details here - // pub async fn download_file(&self, remote_cloud_bucket_details:RemoteCloudBucketDetails, to_system_file_path:String) -> AnyHowResult<> { - // self.bucket_client.download_file_to_disk(object_path, filesystem_path) - // } + // return error or success with meta data. + pub async fn upload_file(&self, file_descriptor:Box, from_system_file_path:&str) -> Result { + let bucket_client = self.get_bucket_with_visbility(file_descriptor.is_public()).await?; - // // return error or success with meta data. - // pub async fn upload_file(&self, from_system_file_path:String) -> Result { - // // get file meta data - // let result = Self::get_file_meta_data(system_file_path.clone())?; - // Ok(result) - // } + // get file meta data + info!("Reading media file: {:?}", from_system_file_path); + // get meta data + let bytes = file_read_bytes(from_system_file_path)?; + let mimetype = get_mimetype_for_bytes(&bytes).unwrap_or("application/octet-stream"); + + let directory = FileBucketDirectory::generate_new( + file_descriptor + ); + + bucket_client.upload_file_with_content_type( + &directory.get_remote_cloud_base_directory(), + bytes.as_ref(), + mimetype + ).await?; + + let result = Self::get_file_meta_data(from_system_file_path)?; + Ok(result) + } // Retrieve the metadata from the file - pub fn get_file_meta_data(system_file_path:String) -> Result { + fn get_file_meta_data(system_file_path:&str) -> Result { let file_size_bytes = file_size(system_file_path.clone())?; let sha256_checksum = sha256_hash_file(system_file_path.clone())?; @@ -111,7 +148,7 @@ mod tests { //use super::RemoteCloudFileClient; #[test] fn test_web_file_manager() { - println!("test") + } } \ No newline at end of file diff --git a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/weights_descriptor.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/weights_descriptor.rs index e69de29bb2..b2a332ba7a 100644 --- a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/weights_descriptor.rs +++ b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/weights_descriptor.rs @@ -0,0 +1,77 @@ +use super::file_descriptor::FileDescriptor; + +pub struct WeightsLoRADescriptor {} + + +const REMOTE_FILE_DIRECTORY: &str = "/weights"; + +impl FileDescriptor for WeightsLoRADescriptor { + fn remote_directory_path(&self) -> &str { + return REMOTE_FILE_DIRECTORY; + } + // this will be the type of file peroid is handled by the file formatter + // e.g safetensors bin jpg + fn get_suffix(&self)->String { + return "safetensors".to_string(); + } + // This will be the prefix of the media type or the weights type. + // name of the weights or the name of the media type + // vall-e_prompt, loRA, sd15, sdxl when implmenting add to the end + fn get_prefix(&self)->String { + return "loRA".to_string(); + } + + // This will be ensure that the right bucket is picked + fn is_public(&self) -> bool { + true + } +} + +pub struct WeightsSD15Descriptor {} + +impl FileDescriptor for WeightsSD15Descriptor { + fn remote_directory_path(&self) -> &str { + return REMOTE_FILE_DIRECTORY; + } + // this will be the type of file peroid is handled by the file formatter + // e.g safetensors bin jpg + fn get_suffix(&self)->String { + return "safetensors".to_string(); + } + // This will be the prefix of the media type or the weights type. + // name of the weights or the name of the media type + // vall-e_prompt, SD15, sd15, sdxl when implmenting add to the end + fn get_prefix(&self)->String { + return "sd15".to_string(); + } + + // This will be ensure that the right bucket is picked + fn is_public(&self) -> bool { + true + } +} + + +pub struct WeightsSDXLDescriptor {} + +impl FileDescriptor for WeightsSDXLDescriptor { + fn remote_directory_path(&self) -> &str { + return REMOTE_FILE_DIRECTORY; + } + // this will be the type of file peroid is handled by the file formatter + // e.g safetensors bin jpg + fn get_suffix(&self)->String { + return "safetensors".to_string(); + } + // This will be the prefix of the media type or the weights type. + // name of the weights or the name of the media type + // vall-e_prompt, SD15, sd15, sdxl when implmenting add to the end + fn get_prefix(&self)->String { + return "sdxl".to_string(); + } + + // This will be ensure that the right bucket is picked + fn is_public(&self) -> bool { + true + } +} \ No newline at end of file From 0d58176f0f70d3105b7b3f28892cf9428a9b7ba8 Mon Sep 17 00:00:00 2001 From: Michael Chung Date: Wed, 20 Dec 2023 02:23:45 -0500 Subject: [PATCH 096/124] Minor bug fixes then testing. --- .../remote_file_manager/remote_cloud_file_manager.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_file_manager.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_file_manager.rs index 58255adefa..ebb3b62e45 100644 --- a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_file_manager.rs +++ b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_file_manager.rs @@ -63,7 +63,7 @@ impl RemoteCloudFileClient { let file_bucket_directory = FileBucketDirectory::from_existing_bucket_details(remote_cloud_bucket_details); let full_remote_cloud_file_path = file_bucket_directory.get_full_remote_cloud_file_path(); let bucket_client = self.get_bucket_with_visbility(file_descriptor.is_public()).await?; - bucket_client.download_file_to_disk(full_remote_cloud_file_path, to_system_file_path); + bucket_client.download_file_to_disk(full_remote_cloud_file_path, to_system_file_path).await?; Ok(()) } @@ -110,19 +110,20 @@ impl RemoteCloudFileClient { info!("Reading media file: {:?}", from_system_file_path); // get meta data let bytes = file_read_bytes(from_system_file_path)?; - let mimetype = get_mimetype_for_bytes(&bytes).unwrap_or("application/octet-stream"); + + let result = Self::get_file_meta_data(from_system_file_path)?; let directory = FileBucketDirectory::generate_new( file_descriptor ); - bucket_client.upload_file_with_content_type( + bucket_client.upload_file_with_content_type_process( &directory.get_remote_cloud_base_directory(), bytes.as_ref(), - mimetype + result.mimetype.as_ref() ).await?; - let result = Self::get_file_meta_data(from_system_file_path)?; + Ok(result) } From 5e04cc6c2f90dd8d7f40e396a4774831f3b717e1 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Wed, 20 Dec 2023 18:15:05 -0500 Subject: [PATCH 097/124] work on tts model migration --- ...c73117057e44766c330caff6ce2c9d48518fd.json | 12 + ...8c2f3888e3061fc8b44291541840fdb706e44.json | 542 ++++++++++++++++++ .../list_whole_tts_models_using_cursor.rs | 341 +++++++++++ .../queries/tts/tts_models/migration/mod.rs | 1 + .../src/queries/tts/tts_models/mod.rs | 1 + 5 files changed, 897 insertions(+) create mode 100644 .sqlx/query-898a2f89d1f3efcb87adaef432cc73117057e44766c330caff6ce2c9d48518fd.json create mode 100644 .sqlx/query-a44c637e84152864a00f0ba58838c2f3888e3061fc8b44291541840fdb706e44.json create mode 100644 crates/lib/mysql_queries/src/queries/tts/tts_models/migration/list_whole_tts_models_using_cursor.rs create mode 100644 crates/lib/mysql_queries/src/queries/tts/tts_models/migration/mod.rs diff --git a/.sqlx/query-898a2f89d1f3efcb87adaef432cc73117057e44766c330caff6ce2c9d48518fd.json b/.sqlx/query-898a2f89d1f3efcb87adaef432cc73117057e44766c330caff6ce2c9d48518fd.json new file mode 100644 index 0000000000..e1c168b7a3 --- /dev/null +++ b/.sqlx/query-898a2f89d1f3efcb87adaef432cc73117057e44766c330caff6ce2c9d48518fd.json @@ -0,0 +1,12 @@ +{ + "db_name": "MySQL", + "query": "\nUPDATE voice_conversion_models\nSET\n maybe_migration_new_model_weights_token = ?\nWHERE token = ?\n ", + "describe": { + "columns": [], + "parameters": { + "Right": 2 + }, + "nullable": [] + }, + "hash": "898a2f89d1f3efcb87adaef432cc73117057e44766c330caff6ce2c9d48518fd" +} diff --git a/.sqlx/query-a44c637e84152864a00f0ba58838c2f3888e3061fc8b44291541840fdb706e44.json b/.sqlx/query-a44c637e84152864a00f0ba58838c2f3888e3061fc8b44291541840fdb706e44.json new file mode 100644 index 0000000000..fc12836f47 --- /dev/null +++ b/.sqlx/query-a44c637e84152864a00f0ba58838c2f3888e3061fc8b44291541840fdb706e44.json @@ -0,0 +1,542 @@ +{ + "db_name": "MySQL", + "query": "\nSELECT\n id,\n token as `token: tokens::tokens::tts_models::TtsModelToken`,\n\n tts_model_type as `tts_model_type: enums::by_table::tts_models::tts_model_type::TtsModelType`,\n\n text_pipeline_type,\n has_self_contained_vocoder,\n has_self_contained_duration_model,\n has_self_contained_pitch_model,\n text_preprocessing_algorithm,\n\n use_default_mel_multiply_factor,\n maybe_custom_mel_multiply_factor,\n maybe_default_pretrained_vocoder,\n maybe_custom_vocoder_token as `maybe_custom_vocoder_token: tokens::tokens::vocoder_models::VocoderModelToken`,\n\n ietf_language_tag,\n ietf_primary_language_subtag,\n\n title,\n description_markdown,\n description_rendered_html,\n\n voice_name,\n actor_name,\n characteristic,\n version_string,\n\n is_front_page_featured,\n is_twitch_featured,\n\n maybe_suggested_unique_bot_command,\n\n original_download_url,\n original_filename,\n file_size_bytes,\n\n creator_user_token as `creator_user_token: tokens::tokens::users::UserToken`,\n\n creator_ip_address_creation,\n creator_ip_address_last_update,\n\n creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n\n private_bucket_hash,\n private_bucket_object_name,\n\n private_bucket_object_is_archive,\n\n user_ratings_total_count,\n user_ratings_positive_count,\n user_ratings_negative_count,\n\n is_public_listing_approved,\n is_locked_from_user_modification,\n is_locked_from_use,\n\n maybe_mod_comments,\n maybe_mod_user_token as `maybe_mod_user_token: tokens::tokens::users::UserToken`,\n\n maybe_migration_new_model_weights_token as `maybe_migration_new_model_weights_token: tokens::tokens::model_weights::ModelWeightToken`,\n\n version,\n\n created_at,\n updated_at,\n\n user_deleted_at,\n mod_deleted_at\n\nFROM tts_models\nWHERE\n id > ?\nORDER BY id ASC\nLIMIT ?\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "id", + "type_info": { + "type": "LongLong", + "flags": "NOT_NULL | PRIMARY_KEY | AUTO_INCREMENT", + "char_set": 63, + "max_size": 20 + } + }, + { + "ordinal": 1, + "name": "token: tokens::tokens::tts_models::TtsModelToken", + "type_info": { + "type": "VarString", + "flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 128 + } + }, + { + "ordinal": 2, + "name": "tts_model_type: enums::by_table::tts_models::tts_model_type::TtsModelType", + "type_info": { + "type": "String", + "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | ENUM", + "char_set": 224, + "max_size": 60 + } + }, + { + "ordinal": 3, + "name": "text_pipeline_type", + "type_info": { + "type": "VarString", + "flags": "BINARY", + "char_set": 224, + "max_size": 256 + } + }, + { + "ordinal": 4, + "name": "has_self_contained_vocoder", + "type_info": { + "type": "Tiny", + "flags": "NOT_NULL", + "char_set": 63, + "max_size": 1 + } + }, + { + "ordinal": 5, + "name": "has_self_contained_duration_model", + "type_info": { + "type": "Tiny", + "flags": "NOT_NULL", + "char_set": 63, + "max_size": 1 + } + }, + { + "ordinal": 6, + "name": "has_self_contained_pitch_model", + "type_info": { + "type": "Tiny", + "flags": "NOT_NULL", + "char_set": 63, + "max_size": 1 + } + }, + { + "ordinal": 7, + "name": "text_preprocessing_algorithm", + "type_info": { + "type": "String", + "flags": "NOT_NULL | BINARY | ENUM", + "char_set": 224, + "max_size": 28 + } + }, + { + "ordinal": 8, + "name": "use_default_mel_multiply_factor", + "type_info": { + "type": "Tiny", + "flags": "NOT_NULL", + "char_set": 63, + "max_size": 1 + } + }, + { + "ordinal": 9, + "name": "maybe_custom_mel_multiply_factor", + "type_info": { + "type": "Double", + "flags": "", + "char_set": 63, + "max_size": 22 + } + }, + { + "ordinal": 10, + "name": "maybe_default_pretrained_vocoder", + "type_info": { + "type": "VarString", + "flags": "BINARY", + "char_set": 224, + "max_size": 256 + } + }, + { + "ordinal": 11, + "name": "maybe_custom_vocoder_token: tokens::tokens::vocoder_models::VocoderModelToken", + "type_info": { + "type": "VarString", + "flags": "MULTIPLE_KEY | BINARY", + "char_set": 224, + "max_size": 128 + } + }, + { + "ordinal": 12, + "name": "ietf_language_tag", + "type_info": { + "type": "VarString", + "flags": "NOT_NULL | BINARY", + "char_set": 224, + "max_size": 256 + } + }, + { + "ordinal": 13, + "name": "ietf_primary_language_subtag", + "type_info": { + "type": "VarString", + "flags": "NOT_NULL | BINARY", + "char_set": 224, + "max_size": 48 + } + }, + { + "ordinal": 14, + "name": "title", + "type_info": { + "type": "VarString", + "flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 1020 + } + }, + { + "ordinal": 15, + "name": "description_markdown", + "type_info": { + "type": "Blob", + "flags": "NOT_NULL | BLOB | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 262140 + } + }, + { + "ordinal": 16, + "name": "description_rendered_html", + "type_info": { + "type": "Blob", + "flags": "NOT_NULL | BLOB | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 262140 + } + }, + { + "ordinal": 17, + "name": "voice_name", + "type_info": { + "type": "VarString", + "flags": "BINARY", + "char_set": 224, + "max_size": 1020 + } + }, + { + "ordinal": 18, + "name": "actor_name", + "type_info": { + "type": "VarString", + "flags": "BINARY", + "char_set": 224, + "max_size": 1020 + } + }, + { + "ordinal": 19, + "name": "characteristic", + "type_info": { + "type": "VarString", + "flags": "BINARY", + "char_set": 224, + "max_size": 1020 + } + }, + { + "ordinal": 20, + "name": "version_string", + "type_info": { + "type": "VarString", + "flags": "BINARY", + "char_set": 224, + "max_size": 1020 + } + }, + { + "ordinal": 21, + "name": "is_front_page_featured", + "type_info": { + "type": "Tiny", + "flags": "NOT_NULL", + "char_set": 63, + "max_size": 1 + } + }, + { + "ordinal": 22, + "name": "is_twitch_featured", + "type_info": { + "type": "Tiny", + "flags": "NOT_NULL", + "char_set": 63, + "max_size": 1 + } + }, + { + "ordinal": 23, + "name": "maybe_suggested_unique_bot_command", + "type_info": { + "type": "VarString", + "flags": "UNIQUE_KEY | BINARY", + "char_set": 224, + "max_size": 1020 + } + }, + { + "ordinal": 24, + "name": "original_download_url", + "type_info": { + "type": "VarString", + "flags": "BINARY", + "char_set": 224, + "max_size": 2048 + } + }, + { + "ordinal": 25, + "name": "original_filename", + "type_info": { + "type": "VarString", + "flags": "BINARY", + "char_set": 224, + "max_size": 1020 + } + }, + { + "ordinal": 26, + "name": "file_size_bytes", + "type_info": { + "type": "Long", + "flags": "NOT_NULL", + "char_set": 63, + "max_size": 10 + } + }, + { + "ordinal": 27, + "name": "creator_user_token: tokens::tokens::users::UserToken", + "type_info": { + "type": "VarString", + "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 128 + } + }, + { + "ordinal": 28, + "name": "creator_ip_address_creation", + "type_info": { + "type": "VarString", + "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 160 + } + }, + { + "ordinal": 29, + "name": "creator_ip_address_last_update", + "type_info": { + "type": "VarString", + "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 160 + } + }, + { + "ordinal": 30, + "name": "creator_set_visibility: enums::common::visibility::Visibility", + "type_info": { + "type": "String", + "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | ENUM", + "char_set": 224, + "max_size": 28 + } + }, + { + "ordinal": 31, + "name": "private_bucket_hash", + "type_info": { + "type": "String", + "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 256 + } + }, + { + "ordinal": 32, + "name": "private_bucket_object_name", + "type_info": { + "type": "VarString", + "flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 1020 + } + }, + { + "ordinal": 33, + "name": "private_bucket_object_is_archive", + "type_info": { + "type": "Tiny", + "flags": "NOT_NULL", + "char_set": 63, + "max_size": 1 + } + }, + { + "ordinal": 34, + "name": "user_ratings_total_count", + "type_info": { + "type": "Long", + "flags": "NOT_NULL | UNSIGNED", + "char_set": 63, + "max_size": 10 + } + }, + { + "ordinal": 35, + "name": "user_ratings_positive_count", + "type_info": { + "type": "Long", + "flags": "NOT_NULL | UNSIGNED", + "char_set": 63, + "max_size": 10 + } + }, + { + "ordinal": 36, + "name": "user_ratings_negative_count", + "type_info": { + "type": "Long", + "flags": "NOT_NULL | UNSIGNED", + "char_set": 63, + "max_size": 10 + } + }, + { + "ordinal": 37, + "name": "is_public_listing_approved", + "type_info": { + "type": "Tiny", + "flags": "MULTIPLE_KEY", + "char_set": 63, + "max_size": 1 + } + }, + { + "ordinal": 38, + "name": "is_locked_from_user_modification", + "type_info": { + "type": "Tiny", + "flags": "NOT_NULL | MULTIPLE_KEY", + "char_set": 63, + "max_size": 1 + } + }, + { + "ordinal": 39, + "name": "is_locked_from_use", + "type_info": { + "type": "Tiny", + "flags": "NOT_NULL | MULTIPLE_KEY", + "char_set": 63, + "max_size": 1 + } + }, + { + "ordinal": 40, + "name": "maybe_mod_comments", + "type_info": { + "type": "VarString", + "flags": "BINARY", + "char_set": 224, + "max_size": 1020 + } + }, + { + "ordinal": 41, + "name": "maybe_mod_user_token: tokens::tokens::users::UserToken", + "type_info": { + "type": "VarString", + "flags": "MULTIPLE_KEY | BINARY", + "char_set": 224, + "max_size": 128 + } + }, + { + "ordinal": 42, + "name": "maybe_migration_new_model_weights_token: tokens::tokens::model_weights::ModelWeightToken", + "type_info": { + "type": "VarString", + "flags": "UNIQUE_KEY | BINARY", + "char_set": 224, + "max_size": 128 + } + }, + { + "ordinal": 43, + "name": "version", + "type_info": { + "type": "Long", + "flags": "NOT_NULL", + "char_set": 63, + "max_size": 11 + } + }, + { + "ordinal": 44, + "name": "created_at", + "type_info": { + "type": "Timestamp", + "flags": "NOT_NULL | BINARY | TIMESTAMP", + "char_set": 63, + "max_size": 19 + } + }, + { + "ordinal": 45, + "name": "updated_at", + "type_info": { + "type": "Timestamp", + "flags": "NOT_NULL | BINARY | TIMESTAMP | ON_UPDATE_NOW", + "char_set": 63, + "max_size": 19 + } + }, + { + "ordinal": 46, + "name": "user_deleted_at", + "type_info": { + "type": "Timestamp", + "flags": "BINARY", + "char_set": 63, + "max_size": 19 + } + }, + { + "ordinal": 47, + "name": "mod_deleted_at", + "type_info": { + "type": "Timestamp", + "flags": "BINARY", + "char_set": 63, + "max_size": 19 + } + } + ], + "parameters": { + "Right": 2 + }, + "nullable": [ + false, + false, + false, + true, + false, + false, + false, + false, + false, + true, + true, + true, + false, + false, + false, + false, + false, + true, + true, + true, + true, + false, + false, + true, + true, + true, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + true, + false, + false, + true, + true, + true, + false, + false, + false, + true, + true + ] + }, + "hash": "a44c637e84152864a00f0ba58838c2f3888e3061fc8b44291541840fdb706e44" +} diff --git a/crates/lib/mysql_queries/src/queries/tts/tts_models/migration/list_whole_tts_models_using_cursor.rs b/crates/lib/mysql_queries/src/queries/tts/tts_models/migration/list_whole_tts_models_using_cursor.rs new file mode 100644 index 0000000000..b40243f612 --- /dev/null +++ b/crates/lib/mysql_queries/src/queries/tts/tts_models/migration/list_whole_tts_models_using_cursor.rs @@ -0,0 +1,341 @@ +use anyhow::anyhow; +use chrono::{DateTime, Utc}; +use log::warn; +use sqlx::{MySql, MySqlPool}; +use sqlx::pool::PoolConnection; +use enums::by_table::tts_models::tts_model_type::TtsModelType; + +use enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType; +use enums::common::visibility::Visibility; +use errors::AnyhowResult; +use tokens::tokens::model_weights::ModelWeightToken; +use tokens::tokens::tts_models::TtsModelToken; +use tokens::tokens::users::UserToken; +use tokens::tokens::vocoder_models::VocoderModelToken; +use tokens::tokens::voice_conversion_models::VoiceConversionModelToken; + +use crate::helpers::boolean_converters::{i8_to_bool, nullable_i8_to_optional_bool}; + +/// This is meant to be the entire table +#[derive(Debug)] +pub struct WholeTtsModelRecord { + pub id: i64, + pub token: TtsModelToken, + + pub tts_model_type: TtsModelType, + pub text_pipeline_type: Option, + + pub has_self_contained_vocoder: bool, + pub has_self_contained_duration_model: bool, + pub has_self_contained_pitch_model: bool, + + pub text_preprocessing_algorithm: Option, + + pub use_default_mel_multiply_factor: bool, + pub maybe_custom_mel_multiply_factor: Option, + + pub maybe_default_pretrained_vocoder: Option, + pub maybe_custom_vocoder_token: Option, + + pub ietf_language_tag: String, + pub ietf_primary_language_subtag: String, + + pub title: String, + pub description_markdown: String, + pub description_rendered_html: String, + + pub voice_name: Option, + pub actor_name: Option, + pub characteristic: Option, + pub version_string: Option, + + pub is_front_page_featured: bool, + pub is_twitch_featured: bool, + + pub maybe_suggested_unique_bot_command: Option, + + pub original_download_url: Option, + pub original_filename: Option, + pub file_size_bytes: i32, + + pub creator_user_token: UserToken, + + pub creator_ip_address_creation: String, + pub creator_ip_address_last_update: String, + + pub creator_set_visibility: Visibility, + + pub private_bucket_hash: String, + pub private_bucket_object_name: String, + + pub private_bucket_object_is_archive: bool, + + pub user_ratings_total_count: u32, + pub user_ratings_positive_count: u32, + pub user_ratings_negative_count: u32, + + pub is_public_listing_approved: Option, + pub is_locked_from_user_modification: bool, + pub is_locked_from_use: bool, + + pub maybe_mod_comments: Option, + pub maybe_mod_user_token: Option, + + pub maybe_migration_new_model_weights_token: Option, + + pub version: i32, + + pub created_at: DateTime, + pub updated_at: DateTime, + + pub user_deleted_at: Option>, + pub mod_deleted_at: Option>, +} + +pub async fn list_whole_tts_models_using_cursor( + mysql_pool: &MySqlPool, + page_size: u64, + cursor: u64, +) -> AnyhowResult> { + let mut connection = mysql_pool.acquire().await?; + + let maybe_models + = list_whole_voice_conversion_models(&mut connection, page_size, cursor) + .await; + + let models : Vec = match maybe_models { + Ok(models) => models, + Err(err) => { + match err { + RowNotFound => { + return Ok(Vec::new()); + }, + _ => { + warn!("vc model list query error: {:?}", err); + return Err(anyhow!("vc model list query error")); + } + } + } + }; + + Ok(models.into_iter() + .map(|model| { + WholeTtsModelRecord { + id: model.id, + token: model.token, + tts_model_type: model.tts_model_type, + text_pipeline_type: model.text_pipeline_type, + has_self_contained_vocoder: i8_to_bool(model.has_self_contained_vocoder), + has_self_contained_duration_model: i8_to_bool(model.has_self_contained_duration_model), + has_self_contained_pitch_model: i8_to_bool(model.has_self_contained_pitch_model), + text_preprocessing_algorithm: model.text_preprocessing_algorithm, + use_default_mel_multiply_factor: i8_to_bool(model.use_default_mel_multiply_factor), + maybe_custom_mel_multiply_factor: model.maybe_custom_mel_multiply_factor, + maybe_default_pretrained_vocoder: model.maybe_default_pretrained_vocoder, + title: model.title, + description_markdown: model.description_markdown, + description_rendered_html: model.description_rendered_html, + voice_name: model.voice_name, + actor_name: model.actor_name, + characteristic: model.characteristic, + ietf_language_tag: model.ietf_language_tag, + ietf_primary_language_subtag: model.ietf_primary_language_subtag, + is_front_page_featured: i8_to_bool(model.is_front_page_featured), + is_twitch_featured: i8_to_bool(model.is_twitch_featured), + maybe_suggested_unique_bot_command: model.maybe_suggested_unique_bot_command, + original_download_url: model.original_download_url, + original_filename: model.original_filename, + file_size_bytes: model.file_size_bytes, + creator_user_token: model.creator_user_token, + creator_ip_address_creation: model.creator_ip_address_creation, + creator_ip_address_last_update: model.creator_ip_address_last_update, + creator_set_visibility: model.creator_set_visibility, + private_bucket_hash: model.private_bucket_hash, + private_bucket_object_name: model.private_bucket_object_name, + private_bucket_object_is_archive: i8_to_bool(model.private_bucket_object_is_archive), + user_ratings_total_count: model.user_ratings_total_count, + user_ratings_positive_count: model.user_ratings_positive_count, + user_ratings_negative_count: model.user_ratings_negative_count, + is_public_listing_approved: nullable_i8_to_optional_bool(model.is_public_listing_approved), + is_locked_from_user_modification: i8_to_bool(model.is_locked_from_user_modification), + is_locked_from_use: i8_to_bool(model.is_locked_from_use), + maybe_mod_comments: model.maybe_mod_comments, + maybe_mod_user_token: model.maybe_mod_user_token, + maybe_migration_new_model_weights_token: model.maybe_migration_new_model_weights_token, + version: model.version, + created_at: model.created_at, + updated_at: model.updated_at, + user_deleted_at: model.user_deleted_at, + mod_deleted_at: model.mod_deleted_at, + maybe_custom_vocoder_token: model.maybe_custom_vocoder_token, + version_string: model.version_string + } + }) + .collect::>()) +} + +async fn list_whole_voice_conversion_models( + mysql_connection: &mut PoolConnection, + page_size: u64, + cursor: u64, +) -> AnyhowResult> { + Ok(sqlx::query_as!( + RawRecord, + r#" +SELECT + id, + token as `token: tokens::tokens::tts_models::TtsModelToken`, + + tts_model_type as `tts_model_type: enums::by_table::tts_models::tts_model_type::TtsModelType`, + + text_pipeline_type, + has_self_contained_vocoder, + has_self_contained_duration_model, + has_self_contained_pitch_model, + text_preprocessing_algorithm, + + use_default_mel_multiply_factor, + maybe_custom_mel_multiply_factor, + maybe_default_pretrained_vocoder, + maybe_custom_vocoder_token as `maybe_custom_vocoder_token: tokens::tokens::vocoder_models::VocoderModelToken`, + + ietf_language_tag, + ietf_primary_language_subtag, + + title, + description_markdown, + description_rendered_html, + + voice_name, + actor_name, + characteristic, + version_string, + + is_front_page_featured, + is_twitch_featured, + + maybe_suggested_unique_bot_command, + + original_download_url, + original_filename, + file_size_bytes, + + creator_user_token as `creator_user_token: tokens::tokens::users::UserToken`, + + creator_ip_address_creation, + creator_ip_address_last_update, + + creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`, + + private_bucket_hash, + private_bucket_object_name, + + private_bucket_object_is_archive, + + user_ratings_total_count, + user_ratings_positive_count, + user_ratings_negative_count, + + is_public_listing_approved, + is_locked_from_user_modification, + is_locked_from_use, + + maybe_mod_comments, + maybe_mod_user_token as `maybe_mod_user_token: tokens::tokens::users::UserToken`, + + maybe_migration_new_model_weights_token as `maybe_migration_new_model_weights_token: tokens::tokens::model_weights::ModelWeightToken`, + + version, + + created_at, + updated_at, + + user_deleted_at, + mod_deleted_at + +FROM tts_models +WHERE + id > ? +ORDER BY id ASC +LIMIT ? + "#, + cursor, + page_size + ) + .fetch_all(&mut **mysql_connection) + .await?) +} + +struct RawRecord { + pub id: i64, + pub token: TtsModelToken, + + pub tts_model_type: TtsModelType, + pub text_pipeline_type: Option, + + pub has_self_contained_vocoder: i8, // bool + pub has_self_contained_duration_model: i8, // bool + pub has_self_contained_pitch_model: i8, // bool + + pub text_preprocessing_algorithm: Option, + + pub use_default_mel_multiply_factor: i8, // bool + pub maybe_custom_mel_multiply_factor: Option, + + pub maybe_default_pretrained_vocoder: Option, + pub maybe_custom_vocoder_token: Option, + + pub ietf_language_tag: String, + pub ietf_primary_language_subtag: String, + + pub title: String, + pub description_markdown: String, + pub description_rendered_html: String, + + pub voice_name: Option, + pub actor_name: Option, + pub characteristic: Option, + pub version_string: Option, + + pub is_front_page_featured: i8, // bool + pub is_twitch_featured: i8, // bool + + pub maybe_suggested_unique_bot_command: Option, + + pub original_download_url: Option, + pub original_filename: Option, + pub file_size_bytes: i32, + + pub creator_user_token: UserToken, + + pub creator_ip_address_creation: String, + pub creator_ip_address_last_update: String, + + pub creator_set_visibility: Visibility, + + pub private_bucket_hash: String, + pub private_bucket_object_name: String, + + pub private_bucket_object_is_archive: i8, // bool + + pub user_ratings_total_count: u32, + pub user_ratings_positive_count: u32, + pub user_ratings_negative_count: u32, + + pub is_public_listing_approved: Option, // bool + pub is_locked_from_user_modification: i8, // bool + pub is_locked_from_use: i8, // bool + + pub maybe_mod_comments: Option, + pub maybe_mod_user_token: Option, + + pub maybe_migration_new_model_weights_token: Option, + + pub version: i32, + + pub created_at: DateTime, + pub updated_at: DateTime, + + pub user_deleted_at: Option>, + pub mod_deleted_at: Option>, +} diff --git a/crates/lib/mysql_queries/src/queries/tts/tts_models/migration/mod.rs b/crates/lib/mysql_queries/src/queries/tts/tts_models/migration/mod.rs new file mode 100644 index 0000000000..c4d10df508 --- /dev/null +++ b/crates/lib/mysql_queries/src/queries/tts/tts_models/migration/mod.rs @@ -0,0 +1 @@ +pub mod list_whole_tts_models_using_cursor; \ No newline at end of file diff --git a/crates/lib/mysql_queries/src/queries/tts/tts_models/mod.rs b/crates/lib/mysql_queries/src/queries/tts/tts_models/mod.rs index 418b501882..5e9b31cd7e 100644 --- a/crates/lib/mysql_queries/src/queries/tts/tts_models/mod.rs +++ b/crates/lib/mysql_queries/src/queries/tts/tts_models/mod.rs @@ -9,3 +9,4 @@ pub mod get_tts_model_for_inference_improved; pub mod insert_tts_model_from_download_job; pub mod list_all_tts_model_tokens; pub mod list_tts_models; +pub mod migration; From c715d6795c917787c43362d8c023905bcc735100 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Wed, 20 Dec 2023 21:37:48 -0500 Subject: [PATCH 098/124] Fix download-job; fix Victor's API issue --- .../job/list_available_generic_download_jobs.rs | 6 +++--- .../endpoints/media_files/list_media_files.rs | 16 ++++++++++------ .../media_files/list_media_files_for_user.rs | 16 ++++++++++------ 3 files changed, 23 insertions(+), 15 deletions(-) diff --git a/crates/lib/mysql_queries/src/queries/generic_download/job/list_available_generic_download_jobs.rs b/crates/lib/mysql_queries/src/queries/generic_download/job/list_available_generic_download_jobs.rs index ccd5875e53..b836adfbc5 100644 --- a/crates/lib/mysql_queries/src/queries/generic_download/job/list_available_generic_download_jobs.rs +++ b/crates/lib/mysql_queries/src/queries/generic_download/job/list_available_generic_download_jobs.rs @@ -52,7 +52,7 @@ SELECT id, token, - creator_user_token as `creator_user_token: tokens::tokens::users::UserToken`, + creator_user_token, creator_ip_address, creator_set_visibility, @@ -101,7 +101,7 @@ WHERE id: GenericDownloadJobId(record.id), download_job_token: DownloadJobToken::new(record.token), creator_ip_address: record.creator_ip_address, - creator_user_token: record.creator_user_token, + creator_user_token: UserToken::new_from_str(&record.creator_user_token), // NB: Failure case for parsing visibility - default to private creator_set_visibility: Visibility::from_str(&record.creator_set_visibility) .unwrap_or(Visibility::Private), @@ -144,7 +144,7 @@ struct AvailableDownloadJobRawInternal { pub id: i64, pub token: String, - pub creator_user_token: UserToken, + pub creator_user_token: String, pub creator_ip_address: String, pub creator_set_visibility: String, diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files.rs index df1e91d32d..e1c0869e90 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files.rs @@ -6,6 +6,7 @@ use actix_web::http::StatusCode; use actix_web::web::{Path, Query}; use chrono::{DateTime, Utc}; use log::{info, warn}; +use buckets::public::media_files::bucket_file_path::MediaFileBucketPath; use enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory; use enums::by_table::media_files::media_file_origin_model_type::MediaFileOriginModelType; @@ -46,9 +47,9 @@ pub struct MediaFileListItem { pub maybe_origin_model_token: Option, pub media_type: MediaFileType, - pub public_bucket_directory_hash: String, - pub maybe_public_bucket_prefix: Option, - pub maybe_public_bucket_extension: Option, + + /// URL to the media file. + pub public_bucket_path: String, pub maybe_creator: Option, @@ -180,9 +181,12 @@ pub async fn list_media_files_handler( maybe_origin_model_type: record.maybe_origin_model_type, maybe_origin_model_token: record.maybe_origin_model_token, media_type: record.media_type, - public_bucket_directory_hash: record.public_bucket_directory_hash, - maybe_public_bucket_prefix: record.maybe_public_bucket_prefix, - maybe_public_bucket_extension: record.maybe_public_bucket_extension, + public_bucket_path: MediaFileBucketPath::from_object_hash( + &record.public_bucket_directory_hash, + record.maybe_public_bucket_prefix.as_deref(), + record.maybe_public_bucket_extension.as_deref()) + .get_full_object_path_str() + .to_string(), maybe_creator: UserDetailsLight::from_optional_db_fields_owned( record.maybe_creator_user_token, record.maybe_creator_username, diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files_for_user.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files_for_user.rs index ef03b3dd48..f634072842 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files_for_user.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files_for_user.rs @@ -6,6 +6,7 @@ use actix_web::http::StatusCode; use actix_web::web::{Path, Query}; use chrono::{DateTime, Utc}; use log::{info, warn}; +use buckets::public::media_files::bucket_file_path::MediaFileBucketPath; use enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory; use enums::by_table::media_files::media_file_origin_model_type::MediaFileOriginModelType; @@ -52,9 +53,9 @@ pub struct MediaFileListItem { pub maybe_origin_model_token: Option, pub media_type: MediaFileType, - pub public_bucket_directory_hash: String, - pub maybe_public_bucket_prefix: Option, - pub maybe_public_bucket_extension: Option, + + /// URL to the media file. + pub public_bucket_path: String, pub creator_set_visibility: Visibility, @@ -162,9 +163,12 @@ pub async fn list_media_files_for_user_handler( maybe_origin_model_type: record.maybe_origin_model_type, maybe_origin_model_token: record.maybe_origin_model_token, media_type: record.media_type, - public_bucket_directory_hash: record.public_bucket_directory_hash, - maybe_public_bucket_prefix: record.maybe_public_bucket_prefix, - maybe_public_bucket_extension: record.maybe_public_bucket_extension, + public_bucket_path: MediaFileBucketPath::from_object_hash( + &record.public_bucket_directory_hash, + record.maybe_public_bucket_prefix.as_deref(), + record.maybe_public_bucket_extension.as_deref()) + .get_full_object_path_str() + .to_string(), creator_set_visibility: record.creator_set_visibility, created_at: record.created_at, updated_at: record.updated_at, From dd41c268e44b6c29a5e606bd24b7c63b732fa97c Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Thu, 21 Dec 2023 00:38:04 -0500 Subject: [PATCH 099/124] media file upload --- ...d4076cc0bd7809b6c2cb5740151d6583a6d11.json | 12 + .../generic_synthetic_ids/id_category.rs | 15 +- .../insert_media_file_from_file_upload.rs | 158 ++++++++ .../src/queries/media_files/mod.rs | 1 + .../http_server/endpoints/media_files/mod.rs | 2 + .../upload/drain_multipart_request.rs | 91 +++++ .../endpoints/media_files/upload/mod.rs | 3 + .../upload/process_upload_media_file.rs | 344 ++++++++++++++++++ .../media_files/upload/upload_error.rs | 36 ++ .../media_files/upload_media_file.rs | 64 ++++ .../service/web/storyteller_web/src/routes.rs | 5 + 11 files changed, 729 insertions(+), 2 deletions(-) create mode 100644 .sqlx/query-fed337e365f0bd36cfa543e0ce9d4076cc0bd7809b6c2cb5740151d6583a6d11.json create mode 100644 crates/lib/mysql_queries/src/queries/media_files/insert_media_file_from_file_upload.rs create mode 100644 crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload/drain_multipart_request.rs create mode 100644 crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload/mod.rs create mode 100644 crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload/process_upload_media_file.rs create mode 100644 crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload/upload_error.rs create mode 100644 crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload_media_file.rs diff --git a/.sqlx/query-fed337e365f0bd36cfa543e0ce9d4076cc0bd7809b6c2cb5740151d6583a6d11.json b/.sqlx/query-fed337e365f0bd36cfa543e0ce9d4076cc0bd7809b6c2cb5740151d6583a6d11.json new file mode 100644 index 0000000000..05eba3a4c9 --- /dev/null +++ b/.sqlx/query-fed337e365f0bd36cfa543e0ce9d4076cc0bd7809b6c2cb5740151d6583a6d11.json @@ -0,0 +1,12 @@ +{ + "db_name": "MySQL", + "query": "\nINSERT INTO media_files\nSET\n token = ?,\n\n origin_category = ?,\n origin_product_category = ?,\n\n maybe_origin_model_type = NULL,\n maybe_origin_model_token = NULL,\n\n media_type = ?,\n maybe_mime_type = ?,\n file_size_bytes = ?,\n\n checksum_sha2 = ?,\n\n public_bucket_directory_hash = ?,\n maybe_public_bucket_prefix = ?,\n maybe_public_bucket_extension = ?,\n\n maybe_creator_user_token = ?,\n maybe_creator_anonymous_visitor_token = ?,\n creator_ip_address = ?,\n\n creator_set_visibility = ?,\n\n maybe_creator_file_synthetic_id = ?,\n maybe_creator_category_synthetic_id = ?\n ", + "describe": { + "columns": [], + "parameters": { + "Right": 16 + }, + "nullable": [] + }, + "hash": "fed337e365f0bd36cfa543e0ce9d4076cc0bd7809b6c2cb5740151d6583a6d11" +} diff --git a/crates/_types/enums/src/by_table/generic_synthetic_ids/id_category.rs b/crates/_types/enums/src/by_table/generic_synthetic_ids/id_category.rs index c751d5f5cc..821a66f0ce 100644 --- a/crates/_types/enums/src/by_table/generic_synthetic_ids/id_category.rs +++ b/crates/_types/enums/src/by_table/generic_synthetic_ids/id_category.rs @@ -49,6 +49,10 @@ pub enum IdCategory { #[serde(rename = "model_weights")] ModelWeights, + + /// Files that are uploaded with no general product area they belong to. (Eg. local dev testing) + #[serde(rename = "file_upload")] + FileUpload, } // TODO(bt, 2022-12-21): This desperately needs MySQL integration tests! @@ -68,6 +72,7 @@ impl IdCategory { Self::ZeroShotTtsResult => "zs_tts_result", Self::VideoFilterResult => "video_filter", Self::ModelWeights => "model_weights", + Self::FileUpload => "file_upload", } } @@ -82,6 +87,7 @@ impl IdCategory { "zs_tts_result" => Ok(Self::ZeroShotTtsResult), "video_filter" => Ok(Self::VideoFilterResult), "model_weights" => Ok(Self::ModelWeights), + "file_upload" => Ok(Self::FileUpload), _ => Err(format!("invalid value: {:?}", value)), } } @@ -99,6 +105,7 @@ impl IdCategory { Self::ZeroShotVoiceDataset, Self::ZeroShotVoiceEmbedding, Self::ModelWeights, + Self::FileUpload, ]) } } @@ -121,7 +128,8 @@ mod tests { assert_serialization(IdCategory::ZeroShotVoiceDataset, "zs_dataset"); assert_serialization(IdCategory::ZeroShotVoiceEmbedding, "zs_voice"); assert_serialization(IdCategory::ZeroShotTtsResult, "zs_tts_result"); - assert_serialization(IdCategory::ModelWeights, "model_weights") + assert_serialization(IdCategory::ModelWeights, "model_weights"); + assert_serialization(IdCategory::FileUpload, "file_upload"); } #[test] @@ -135,6 +143,7 @@ mod tests { assert_eq!(IdCategory::ZeroShotVoiceEmbedding.to_str(), "zs_voice"); assert_eq!(IdCategory::ZeroShotTtsResult.to_str(), "zs_tts_result"); assert_eq!(IdCategory::ModelWeights.to_str(), "model_weights"); + assert_eq!(IdCategory::FileUpload.to_str(), "file_upload"); } #[test] @@ -148,13 +157,14 @@ mod tests { assert_eq!(IdCategory::from_str("zs_voice").unwrap(), IdCategory::ZeroShotVoiceEmbedding); assert_eq!(IdCategory::from_str("zs_tts_result").unwrap(), IdCategory::ZeroShotTtsResult); assert_eq!(IdCategory::from_str("model_weights").unwrap(), IdCategory::ModelWeights); + assert_eq!(IdCategory::from_str("file_upload").unwrap(), IdCategory::FileUpload); } #[test] fn all_variants() { // Static check let mut variants = IdCategory::all_variants(); - assert_eq!(variants.len(), 9); + assert_eq!(variants.len(), 10); assert_eq!(variants.pop_first(), Some(IdCategory::MediaFile)); assert_eq!(variants.pop_first(), Some(IdCategory::LipsyncAnimationResult)); assert_eq!(variants.pop_first(), Some(IdCategory::VideoFilterResult)); @@ -164,6 +174,7 @@ mod tests { assert_eq!(variants.pop_first(), Some(IdCategory::ZeroShotVoiceDataset)); assert_eq!(variants.pop_first(), Some(IdCategory::ZeroShotVoiceEmbedding)); assert_eq!(variants.pop_first(), Some(IdCategory::ModelWeights)); + assert_eq!(variants.pop_first(), Some(IdCategory::FileUpload)); assert_eq!(variants.pop_first(), None); // Generated check diff --git a/crates/lib/mysql_queries/src/queries/media_files/insert_media_file_from_file_upload.rs b/crates/lib/mysql_queries/src/queries/media_files/insert_media_file_from_file_upload.rs new file mode 100644 index 0000000000..724118c80b --- /dev/null +++ b/crates/lib/mysql_queries/src/queries/media_files/insert_media_file_from_file_upload.rs @@ -0,0 +1,158 @@ +use anyhow::anyhow; +use sqlx; +use sqlx::MySqlPool; + +use enums::by_table::generic_synthetic_ids::id_category::IdCategory; +use enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory; +use enums::by_table::media_files::media_file_origin_product_category::MediaFileOriginProductCategory; +use enums::by_table::media_files::media_file_type::MediaFileType; +use enums::common::visibility::Visibility; +use errors::AnyhowResult; +use tokens::tokens::anonymous_visitor_tracking::AnonymousVisitorTrackingToken; +use tokens::tokens::media_files::MediaFileToken; +use tokens::tokens::users::UserToken; + +use crate::queries::generic_synthetic_ids::transactional_increment_generic_synthetic_id::transactional_increment_generic_synthetic_id; + +pub enum UploadType { + Filesystem, + DeviceCaptureApi, +} + +pub struct InsertMediaFileFromUploadArgs<'a> { + pub pool: &'a MySqlPool, + + pub maybe_creator_user_token: Option<&'a UserToken>, + pub maybe_creator_anonymous_visitor_token: Option<&'a AnonymousVisitorTrackingToken>, + pub creator_ip_address: &'a str, + pub creator_set_visibility: Visibility, + + pub upload_type: UploadType, + + pub media_file_type: MediaFileType, + pub maybe_mime_type: Option<&'a str>, + pub file_size_bytes: u64, + pub duration_millis: u64, + pub sha256_checksum: &'a str, + + // TODO: Media duration. + //pub duration_millis: u64, + + pub public_bucket_directory_hash: &'a str, + pub maybe_public_bucket_prefix: Option<&'a str>, + pub maybe_public_bucket_extension: Option<&'a str>, +} + +pub async fn insert_media_file_from_file_upload( + args: InsertMediaFileFromUploadArgs<'_> +) -> AnyhowResult<(MediaFileToken, u64)> +{ + let token = MediaFileToken::generate(); + + let origin_category = match args.upload_type { + UploadType::Filesystem => MediaFileOriginCategory::Upload, + UploadType::DeviceCaptureApi => MediaFileOriginCategory::DeviceApi, + }; + + let mut maybe_creator_file_synthetic_id : Option = None; + let mut maybe_creator_category_synthetic_id : Option = None; + + let mut transaction = args.pool.begin().await?; + + if let Some(user_token) = args.maybe_creator_user_token.as_deref() { + + let next_media_file_id = transactional_increment_generic_synthetic_id( + &user_token, + IdCategory::MediaFile, + &mut transaction + ).await?; + + let next_voice_conversion_id = transactional_increment_generic_synthetic_id( + &user_token, + IdCategory::FileUpload, + &mut transaction + ).await?; + + maybe_creator_file_synthetic_id = Some(next_media_file_id); + maybe_creator_category_synthetic_id = Some(next_voice_conversion_id); + } + + const ORIGIN_PRODUCT_CATEGORY : MediaFileOriginProductCategory = MediaFileOriginProductCategory::Unknown; + + let record_id = { + let query_result = sqlx::query!( + r#" +INSERT INTO media_files +SET + token = ?, + + origin_category = ?, + origin_product_category = ?, + + maybe_origin_model_type = NULL, + maybe_origin_model_token = NULL, + + media_type = ?, + maybe_mime_type = ?, + file_size_bytes = ?, + + checksum_sha2 = ?, + + public_bucket_directory_hash = ?, + maybe_public_bucket_prefix = ?, + maybe_public_bucket_extension = ?, + + maybe_creator_user_token = ?, + maybe_creator_anonymous_visitor_token = ?, + creator_ip_address = ?, + + creator_set_visibility = ?, + + maybe_creator_file_synthetic_id = ?, + maybe_creator_category_synthetic_id = ? + "#, + token.as_str(), + + origin_category.to_str(), + ORIGIN_PRODUCT_CATEGORY.to_str(), + + args.media_file_type.to_str(), + args.maybe_mime_type, + args.file_size_bytes, + + args.sha256_checksum, + + args.public_bucket_directory_hash, + args.maybe_public_bucket_prefix, + args.maybe_public_bucket_extension, + + args.maybe_creator_user_token, + args.maybe_creator_anonymous_visitor_token, + args.creator_ip_address, + + args.creator_set_visibility.to_str(), + + maybe_creator_file_synthetic_id, + maybe_creator_category_synthetic_id, + ) + .execute(&mut *transaction) + .await; + + let record_id = match query_result { + Ok(res) => { + res.last_insert_id() + }, + Err(err) => { + // TODO: handle better + //transaction.rollback().await?; + return Err(anyhow!("Mysql error: {:?}", err)); + } + }; + + record_id + }; + + transaction.commit().await?; + + Ok((token, record_id)) +} diff --git a/crates/lib/mysql_queries/src/queries/media_files/mod.rs b/crates/lib/mysql_queries/src/queries/media_files/mod.rs index cedc16583c..cfdc3eb3c8 100644 --- a/crates/lib/mysql_queries/src/queries/media_files/mod.rs +++ b/crates/lib/mysql_queries/src/queries/media_files/mod.rs @@ -2,6 +2,7 @@ pub mod delete_media_file; pub mod get_media_file; pub mod insert_media_file_from_cli_tool; pub mod insert_media_file_from_face_animation; +pub mod insert_media_file_from_file_upload; pub mod insert_media_file_from_rerender; pub mod insert_media_file_from_tacotron2; pub mod insert_media_file_from_voice_conversion; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/mod.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/mod.rs index 8365645e1f..321debe164 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/mod.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/mod.rs @@ -5,3 +5,5 @@ pub mod list_featured_media_files; pub mod list_media_files; pub mod list_media_files_for_user; pub mod update_media_file; +pub mod upload; +pub mod upload_media_file; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload/drain_multipart_request.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload/drain_multipart_request.rs new file mode 100644 index 0000000000..708eb6cc86 --- /dev/null +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload/drain_multipart_request.rs @@ -0,0 +1,91 @@ +use actix_multipart::Multipart; +use actix_web::web::BytesMut; +use futures::TryStreamExt; +use log::warn; + +use errors::AnyhowResult; +use tokens::tokens::zs_voice_datasets::ZsVoiceDatasetToken; + +use crate::http_server::web_utils::read_multipart_field_bytes::{checked_read_multipart_bytes, read_multipart_field_as_text}; + +pub struct MediaFileUploadData { + pub uuid_idempotency_token: Option, + pub file_name: Option, + pub file_bytes: Option, + pub media_source: MediaFileUploadSource, +} + +/// Where the frontend tells us the file came from. +#[derive(Eq, PartialEq, Clone, Copy)] +pub enum MediaFileUploadSource { + Unknown, + /// Eg. from the user's filesystem + UserFile, + /// Eg. the web audio API in Javascript. + UserDeviceApi, +} + +/// Pull common parts out of multipart media HTTP requests, typically for handling file uploads. +pub async fn drain_multipart_request(mut multipart_payload: Multipart) -> AnyhowResult { + let mut uuid_idempotency_token = None; + let mut file_bytes = None; + let mut file_name = None; + let mut media_source = None; + + while let Ok(Some(mut field)) = multipart_payload.try_next().await { + let mut field_name = None; + let mut field_filename = None; + + if let content_disposition = field.content_disposition() { + field_name = content_disposition.get_name() + .map(|s| s.to_string()); + field_filename = content_disposition.get_filename() // NB: Only used for the file bytes. + .map(|s| s.to_string()); + } + + match field_name.as_deref() { + Some("uuid_idempotency_token") => { + uuid_idempotency_token = read_multipart_field_as_text(&mut field).await + .map_err(|e| { + warn!("Error reading idempotency token: {:}", &e); + e + })?; + }, + Some("file") => { + file_name = field_filename.clone(); + file_bytes = checked_read_multipart_bytes(&mut field).await + .map_err(|e| { + warn!("Error reading audio upload: {:}", &e); + e + })?; + }, + Some("source") => { + media_source = read_multipart_field_as_text(&mut field).await + .map_err(|e| { + warn!("Error reading source: {:}", &e); + e + })?; + }, + _ => continue, + } + } + + let media_source = match media_source.as_deref() { + Some("device") => MediaFileUploadSource::UserDeviceApi, + Some("file") => MediaFileUploadSource::UserFile, + _ => { + if file_name.as_deref() == Some("blob") { + MediaFileUploadSource::UserDeviceApi + } else { + MediaFileUploadSource::Unknown + } + }, + }; + + Ok(MediaFileUploadData { + uuid_idempotency_token, + file_name, + file_bytes, + media_source, + }) +} diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload/mod.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload/mod.rs new file mode 100644 index 0000000000..d98cfbc5af --- /dev/null +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload/mod.rs @@ -0,0 +1,3 @@ +pub mod drain_multipart_request; +pub mod process_upload_media_file; +pub mod upload_error; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload/process_upload_media_file.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload/process_upload_media_file.rs new file mode 100644 index 0000000000..df23ab1240 --- /dev/null +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload/process_upload_media_file.rs @@ -0,0 +1,344 @@ +use std::collections::HashSet; +use std::sync::Arc; + +use actix_multipart::Multipart; +use actix_web::{HttpRequest, web}; +use log::{error, info, warn}; + +use buckets::public::media_files::bucket_file_path::MediaFileBucketPath; +use enums::by_table::media_files::media_file_type::MediaFileType; +use enums::common::visibility::Visibility; +use hashing::sha256::sha256_hash_bytes::sha256_hash_bytes; +use http_server_common::request::get_request_ip::get_request_ip; +use media::decode_basic_audio_info::decode_basic_audio_bytes_info; +use mimetypes::mimetype_for_bytes::get_mimetype_for_bytes; +use mysql_queries::queries::media_files::insert_media_file_from_file_upload::{insert_media_file_from_file_upload, InsertMediaFileFromUploadArgs, UploadType}; +use tokens::tokens::media_files::MediaFileToken; + +use crate::http_server::endpoints::media_files::upload::drain_multipart_request::{drain_multipart_request, MediaFileUploadSource}; +use crate::http_server::endpoints::media_files::upload::upload_error::MediaFileUploadError; +use crate::server_state::ServerState; +use crate::validations::validate_idempotency_token_format::validate_idempotency_token_format; + +// TODO(bt,2023-12-20): THIS CODE NEEDS CLEANUP. This has been cargo culted three+ times. +// It's ridiculous and complicated. + +pub enum SuccessCase { + MediaAlreadyUploaded { + existing_media_file_token: MediaFileToken, + }, + MediaSuccessfullyUploaded { + media_file_token: MediaFileToken, + } +} + +impl SuccessCase { + pub fn to_media_token(self) -> MediaFileToken { + match self { + SuccessCase::MediaAlreadyUploaded { existing_media_file_token } => existing_media_file_token, + SuccessCase::MediaSuccessfullyUploaded { media_file_token } => media_file_token, + } + } +} + +pub async fn process_upload_media_file( + http_request: &HttpRequest, + server_state: &web::Data>, + mut multipart_payload: Multipart, + allowed_mimetypes: &HashSet<&'static str>, +) -> Result { + + let mut mysql_connection = server_state.mysql_pool + .acquire() + .await + .map_err(|err| { + error!("MySql pool error: {:?}", err); + MediaFileUploadError::ServerError + })?; + + // ==================== READ SESSION ==================== // + + let maybe_user_session = server_state + .session_checker + .maybe_get_user_session_from_connection(http_request, &mut mysql_connection) + .await + .map_err(|e| { + error!("Session checker error: {:?}", e); + MediaFileUploadError::ServerError + })?; + + let maybe_avt_token = server_state + .avt_cookie_manager + .get_avt_token_from_request(&http_request); + + // ==================== BANNED USERS ==================== // + + if let Some(ref user) = maybe_user_session { + if user.is_banned { + return Err(MediaFileUploadError::NotAuthorized); + } + } + + // ==================== RATE LIMIT ==================== // + + let rate_limiter = match maybe_user_session { + None => &server_state.redis_rate_limiters.file_upload_logged_out, + Some(ref _session) => &server_state.redis_rate_limiters.file_upload_logged_in, + }; + + if let Err(_err) = rate_limiter.rate_limit_request(&http_request) { + return Err(MediaFileUploadError::RateLimited); + } + + // ==================== READ MULTIPART REQUEST ==================== // + + let upload_media_request = drain_multipart_request(multipart_payload) + .await + .map_err(|e| { + // TODO: Error handling could be nicer. + MediaFileUploadError::BadInput("bad request".to_string()) + })?; + + let uuid_idempotency_token = upload_media_request.uuid_idempotency_token + .ok_or(MediaFileUploadError::BadInput("no uuid".to_string()))?; + + // TODO(bt,2023-12-20): Generic table for this. + //let maybe_existing_upload = + // get_media_upload_by_uuid_with_connection(&uuid_idempotency_token, &mut mysql_connection) + // .await; + + //match maybe_existing_upload { + // Err(err) => { + // error!("Error checking for previous upload: {:?}", err); + // return Err(MediaFileUploadError::ServerError); + // } + // Ok(Some(upload)) => { + // // File already uploaded and frontend didn't protect us. + // return Ok(SuccessCase::MediaAlreadyUploaded { + // existing_media_file_token: upload.token, + // }); + // } + // Ok(None) => { + // // Proceed. + // } + //} + + if let Err(reason) = validate_idempotency_token_format(&uuid_idempotency_token) { + return Err(MediaFileUploadError::BadInput(reason)); + } + + let creator_set_visibility = maybe_user_session + .as_ref() + .map(|user_session| user_session.preferred_tts_result_visibility) // TODO: We need a new type of visibility control. + .unwrap_or(Visibility::default()); + + let ip_address = get_request_ip(&http_request); + + let maybe_user_token = maybe_user_session + .map(|session| session.get_strongly_typed_user_token()); + + let maybe_file_size_bytes = upload_media_request.file_bytes + .as_ref() + .map(|bytes| bytes.len()); + + info!("Upload maybe filesize: {:?}", maybe_file_size_bytes); + + let maybe_mimetype = upload_media_request.file_bytes + .as_ref() + .map(|bytes| get_mimetype_for_bytes(bytes.as_ref())) + .flatten(); + + let bytes = match upload_media_request.file_bytes { + None => return Err(MediaFileUploadError::BadInput("missing file contents".to_string())), + Some(bytes) => bytes, + }; + + let hash = sha256_hash_bytes(&bytes) + .map_err(|io_error| { + error!("Problem hashing bytes: {:?}", io_error); + MediaFileUploadError::ServerError + })?; + + let file_size_bytes = bytes.len(); + + let mut maybe_duration_millis = None; + let mut maybe_codec_name = None; + let mut media_file_type = None; + + if let Some(mimetype) = maybe_mimetype.as_deref() { + + if !allowed_mimetypes.contains(mimetype) { + // NB: Don't let our error message inject malicious strings + let filtered_mimetype = mimetype + .chars() + .filter(|c| c.is_ascii()) + .filter(|c| c.is_alphanumeric() || *c == '/') + .collect::(); + return Err(MediaFileUploadError::BadInput(format!("unpermitted mime type: {}", &filtered_mimetype))); + } + + // NB: .aiff (audio/aiff) isn't supported by Symphonia: + // It contains uncompressed PCM-encoded audio similar to wav. + // See: https://github.com/pdeljanov/Symphonia/issues/75 + // NB: The following formats are not supported by Symphonia and + // do not have any open issues filed. They may simply be too old: + // - .wma (audio/x-ms-wma) + // - .avi (video/x-msvideo) + media_file_type = match mimetype { + // Audio + "audio/aac" /* .aac */ => Some(MediaFileType::Audio), + "audio/m4a" /* .m4a */ => Some(MediaFileType::Audio), + "audio/mpeg" /* .mp3 */ => Some(MediaFileType::Audio), + "audio/ogg" /* .ogg */ => Some(MediaFileType::Audio), + "audio/opus" /* .opus */ => Some(MediaFileType::Audio), + "audio/x-flac" /* .flac */ => Some(MediaFileType::Audio), + "audio/x-wav" /* .wav */ => Some(MediaFileType::Audio), + // Image + "image/jpeg" /* .jpg */ => Some(MediaFileType::Image), + "image/png" /* .png */ => Some(MediaFileType::Image), + "image/webp" /* .webp */ => Some(MediaFileType::Image), + // Video + "video/mp4" /* .mp4 */ => Some(MediaFileType::Video), + "video/quicktime" /* .mov */ => Some(MediaFileType::Video), + "video/webm" /* .webm */ => Some(MediaFileType::Video), + _ => None, + }; + + let do_audio_decode = match mimetype { + // TODO: Revisit when Safari can send us this metadata consistently + "audio/mp4" | "video/mp4" => false, + "audio/opus" => { + // TODO/FIXME(bt, 2023-05-19): Symphonia is currently broken for Firefox's opus. + // We're on an off-master branch that may resolve the problem in the future, but for now + // it panics as follows: + // + // [2023-05-19T10:25:34Z INFO symphonia_core::probe] found a possible format marker within [4f, 67, 67, 53, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, d4, c5] @ 0+2 bytes. + // [2023-05-19T10:25:34Z INFO symphonia_core::probe] found the format marker [4f, 67, 67, 53] @ 0+2 bytes. + // [2023-05-19T10:25:34Z DEBUG symphonia_format_ogg::page] grow page buffer to 8192 bytes + // [2023-05-19T10:25:34Z INFO symphonia_format_ogg::demuxer] starting new physical stream + // [2023-05-19T10:25:34Z INFO symphonia_format_ogg::demuxer] selected opus mapper for stream with serial=0x19aac5d4 + // [2023-05-19T10:25:34Z INFO media::decode_basic_audio_info] Probed! + // [2023-05-19T10:25:34Z INFO media::decode_basic_audio_info] Find audio track... + // [2023-05-19T10:25:34Z INFO media::decode_basic_audio_info] Found audio track (maybe) + // [2023-05-19T10:25:34Z INFO media::decode_basic_audio_info] Maybe track duration: None + // [2023-05-19T10:25:34Z INFO media::decode_basic_audio_info] Maybe codec short name: Some("opus") + // [2023-05-19T10:25:34Z INFO media::decode_basic_audio_info] Opus handler + // [2023-05-19T10:25:34Z INFO media::decode_basic_audio_info] Media source stream + // [2023-05-19T10:25:34Z INFO media::decode_webm_opus_info] decode_mkv : options... + // [2023-05-19T10:25:34Z INFO media::decode_webm_opus_info] decode_mkv : try_read... + // [2023-05-19T10:25:34Z DEBUG symphonia_format_mkv::ebml] element with tag: 4F67 + // thread 'actix-rt|system:0|arbiter:1' panicked at 'assertion failed: `(left == right)` + // left: `Unknown`, + // right: `Ebml`: EBML element type must be checked before calling this function', /Users/bt/.cargo/git/checkouts/symphonia-8fbe6c90fc095688/e1a7009/symphonia-format-mkv/src/ebml.rs:335:9 + false + } + // Also, don't decode images + "image/jpeg" => false, + "image/png" => false, + "image/webp" => false, + _ => true, + }; + + if do_audio_decode && media_file_type.is_some() { + let basic_info = decode_basic_audio_bytes_info( + bytes.as_ref(), + Some(mimetype), + None + ).map_err(|e| { + warn!("file decoding error: {:?}", e); + MediaFileUploadError::BadInput("could not decode file".to_string()) + })?; + + maybe_duration_millis = basic_info.duration_millis; + maybe_codec_name = basic_info.codec_name; + } + } + + let media_file_type = match media_file_type { + Some(m) => m, + None => { + warn!("Invalid mimetype: {:?}", maybe_mimetype); + return Err(MediaFileUploadError::BadInput(format!("unknown mimetype: {:?}", maybe_mimetype))) + }, + }; + + let upload_type = match upload_media_request.media_source { + MediaFileUploadSource::Unknown => UploadType::Filesystem, + MediaFileUploadSource::UserFile => UploadType::Filesystem, + MediaFileUploadSource::UserDeviceApi => UploadType::DeviceCaptureApi, + }; + + // TODO: Clean up code + let mime_type = match maybe_mimetype { + Some(m) => m, + None => { + warn!("Missing mimetype!"); + return Err(MediaFileUploadError::BadInput("Missing mimetype".to_string())); + }, + }; + + // TODO(bt,2023-12-20): Reasonable extensions. + let extension = match mime_type { + // Audio + "audio/aac" /* .aac */ => Some(".aac"), + "audio/m4a" /* .m4a */ => Some(".m4a"), + "audio/mpeg" /* .mp3 */ => Some(".mp3"), + "audio/ogg" /* .ogg */ => Some(".ogg"), + "audio/opus" /* .opus */ => Some(".opus"), + "audio/x-flac" /* .flac */ => Some(".flac"), + "audio/x-wav" /* .wav */ => Some(".wav"), + // Image + "image/jpeg" /* .jpg */ => Some(".jpg"), + "image/png" /* .png */ => Some(".png"), + "image/webp" /* .webp */ => Some(".webp"), + // Video + "video/mp4" /* .mp4 */ => Some(".mp4"), + "video/quicktime" /* .mov */ => Some(".mov"), + "video/webm" /* .webm */ => Some(".webm"), + _ => None, + }; + + const PREFIX : Option<&str> = Some("upload_"); + + let public_upload_path = MediaFileBucketPath::generate_new(PREFIX, extension); + + info!("Uploading media to bucket path: {}", public_upload_path.get_full_object_path_str()); + + server_state.public_bucket_client.upload_file_with_content_type( + public_upload_path.get_full_object_path_str(), + bytes.as_ref(), + mime_type) + .await + .map_err(|e| { + warn!("Upload media bytes to bucket error: {:?}", e); + MediaFileUploadError::ServerError + })?; + + let (token, record_id) = insert_media_file_from_file_upload(InsertMediaFileFromUploadArgs { + maybe_creator_user_token: maybe_user_token.as_ref(), + maybe_creator_anonymous_visitor_token: maybe_avt_token.as_ref(), + creator_ip_address: &ip_address, + creator_set_visibility, + upload_type, + media_file_type, + maybe_mime_type: Some(mime_type), + file_size_bytes: file_size_bytes as u64, + duration_millis: 0, // TODO + sha256_checksum: &hash, + public_bucket_directory_hash: public_upload_path.get_object_hash(), + maybe_public_bucket_prefix: PREFIX, + maybe_public_bucket_extension: extension, + pool: &server_state.mysql_pool, + }) + .await + .map_err(|err| { + warn!("New generic download creation DB error: {:?}", err); + MediaFileUploadError::ServerError + })?; + + info!("new media file id: {} token: {:?}", record_id, &token); + + Ok(SuccessCase::MediaSuccessfullyUploaded { + media_file_token: token, + }) +} diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload/upload_error.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload/upload_error.rs new file mode 100644 index 0000000000..39db17e7ed --- /dev/null +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload/upload_error.rs @@ -0,0 +1,36 @@ +use actix_web::error::ResponseError; +use actix_web::http::StatusCode; +use actix_web::HttpResponse; + +use http_server_common::response::serialize_as_json_error::serialize_as_json_error; + +#[derive(Debug, Serialize)] +pub enum MediaFileUploadError { + BadInput(String), + NotAuthorized, + MustBeLoggedIn, + ServerError, + RateLimited, +} + +impl ResponseError for MediaFileUploadError { + fn status_code(&self) -> StatusCode { + match *self { + MediaFileUploadError::BadInput(_) => StatusCode::BAD_REQUEST, + MediaFileUploadError::NotAuthorized => StatusCode::UNAUTHORIZED, + MediaFileUploadError::MustBeLoggedIn => StatusCode::UNAUTHORIZED, + MediaFileUploadError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, + MediaFileUploadError::RateLimited => StatusCode::TOO_MANY_REQUESTS, + } + } + + fn error_response(&self) -> HttpResponse { + serialize_as_json_error(self) + } +} + +impl std::fmt::Display for MediaFileUploadError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } +} diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload_media_file.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload_media_file.rs new file mode 100644 index 0000000000..118a1f267c --- /dev/null +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload_media_file.rs @@ -0,0 +1,64 @@ +use std::collections::HashSet; +use std::sync::Arc; + +use actix_multipart::Multipart; +use actix_web::{HttpRequest, HttpResponse, web}; +use once_cell::sync::Lazy; +use tokens::tokens::media_files::MediaFileToken; +use crate::http_server::endpoints::media_files::upload::process_upload_media_file::process_upload_media_file; + + +use crate::http_server::endpoints::media_files::upload::upload_error::MediaFileUploadError; +use crate::server_state::ServerState; + +#[derive(Serialize)] +pub struct UploadMediaSuccessResponse { + pub success: bool, + pub media_file_token: MediaFileToken, +} + +static ALLOWED_MIME_TYPES : Lazy> = Lazy::new(|| { + HashSet::from([ + // Audio + "audio/aac", + "audio/m4a", + "audio/mpeg", + "audio/ogg", + "audio/opus", + "audio/x-flac", + "audio/x-wav", + // Mixed + "audio/mp4", // iPhone seems to upload these as audio + // Video + "video/mp4", + "video/webm", + //"video/quicktime", + ]) +}); + +pub async fn upload_media_file_handler( + http_request: HttpRequest, + server_state: web::Data>, + mut multipart_payload: Multipart, +) -> Result { + + let response = process_upload_media_file( + &http_request, + &server_state, + multipart_payload, + &ALLOWED_MIME_TYPES).await?; + + let media_file_token = response.to_media_token(); + + let response = UploadMediaSuccessResponse { + success: true, + media_file_token, + }; + + let body = serde_json::to_string(&response) + .map_err(|e| MediaFileUploadError::ServerError)?; + + return Ok(HttpResponse::Ok() + .content_type("application/json") + .body(body)); +} diff --git a/crates/service/web/storyteller_web/src/routes.rs b/crates/service/web/storyteller_web/src/routes.rs index aafc1d1442..7b5dfcea51 100644 --- a/crates/service/web/storyteller_web/src/routes.rs +++ b/crates/service/web/storyteller_web/src/routes.rs @@ -44,6 +44,7 @@ use crate::http_server::endpoints::media_files::list_featured_media_files::list_ use crate::http_server::endpoints::media_files::list_media_files::list_media_files_handler; use crate::http_server::endpoints::media_files::list_media_files_for_user::list_media_files_for_user_handler; use crate::http_server::endpoints::media_files::update_media_file::update_media_file_handler; +use crate::http_server::endpoints::media_files::upload_media_file::upload_media_file_handler; use crate::http_server::endpoints::media_uploads::list_user_media_uploads_of_type::list_user_media_uploads_of_type_handler; use crate::http_server::endpoints::media_uploads::upload_audio::upload_audio_handler; use crate::http_server::endpoints::media_uploads::upload_image::upload_image_handler; @@ -1035,6 +1036,10 @@ fn add_media_file_routes (app: App) -> App .route(web::get().to(list_media_files_for_user_handler)) .route(web::head().to(|| HttpResponse::Ok())) ) + .service(web::resource("/upload") + .route(web::post().to(upload_media_file_handler)) + .route(web::head().to(|| HttpResponse::Ok())) + ) ) } From 20b950794c72fc1334543611fa0282dd38feb5b8 Mon Sep 17 00:00:00 2001 From: Michael Chung Date: Thu, 21 Dec 2023 00:40:17 -0500 Subject: [PATCH 100/124] Ok it builds need to test it using a mock. --- .../src/seeding/seed_model_weights.rs | 2 +- .../cloud_storage/src/bucket_client.rs | 3 +- .../remote_file_manager/file_descriptor.rs | 3 - .../src/remote_file_manager/file_directory.rs | 4 +- .../src/remote_file_manager/file_meta_data.rs | 1 + .../src/remote_file_manager/mod.rs | 7 +- .../remote_cloud_file_manager.rs | 173 ++++++++---------- .../remote_file_manager/weights_descriptor.rs | 1 - 8 files changed, 92 insertions(+), 102 deletions(-) diff --git a/crates/cli/dev-database-seed/src/seeding/seed_model_weights.rs b/crates/cli/dev-database-seed/src/seeding/seed_model_weights.rs index 004597c2f4..4c9a279a44 100644 --- a/crates/cli/dev-database-seed/src/seeding/seed_model_weights.rs +++ b/crates/cli/dev-database-seed/src/seeding/seed_model_weights.rs @@ -25,7 +25,7 @@ use tokens::tokens::users::UserToken; use crate::bucket_clients::BucketClients; use crate::seeding::users::HANASHI_USER_TOKEN; - +use std::result::Result::Ok; pub async fn seed_weights_files( mysql_pool: &Pool, maybe_bucket_clients: Option<&BucketClients> diff --git a/crates/lib/api_clients/cloud_storage/src/bucket_client.rs b/crates/lib/api_clients/cloud_storage/src/bucket_client.rs index 8c3f2a6ba4..577058cfd4 100644 --- a/crates/lib/api_clients/cloud_storage/src/bucket_client.rs +++ b/crates/lib/api_clients/cloud_storage/src/bucket_client.rs @@ -11,6 +11,7 @@ use s3::region::Region; use tokio::fs::File; use tokio::io::AsyncReadExt; use std::error::Error; + #[derive(Clone)] pub struct BucketClient { bucket: Bucket, @@ -225,7 +226,7 @@ impl BucketClient { &self, object_path: P, filesystem_path: Q, - ) -> anyhow::Result<()> { + ) -> AnyhowResult<()> { let object_path_str = object_path.as_ref() .to_str() .map(|s| s.to_string()) diff --git a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/file_descriptor.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/file_descriptor.rs index e265091162..3195736e0f 100644 --- a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/file_descriptor.rs +++ b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/file_descriptor.rs @@ -1,8 +1,5 @@ // Describes the file and how it will be saved to GCBucket // where the file should be stored based off the descriptor -use std::path::PathBuf; -use crockford::crockford_entropy_lower; -use buckets::util::hashed_directory_path_long_string; // DEFAULT IMPLEMENTATION const REMOTE_FILE_DIRECTORY: &str = "/implement_google_cloud_storage_bucket_name"; diff --git a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/file_directory.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/file_directory.rs index c55863670f..70274a9f9c 100644 --- a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/file_directory.rs +++ b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/file_directory.rs @@ -3,7 +3,8 @@ use std::path::PathBuf; use crockford::crockford_entropy_lower; use buckets::util::hashed_directory_path_long_string; use crate::remote_file_manager::file_descriptor::FileDescriptor; -use crate::remote_file_manager::remote_cloud_file_manager::RemoteCloudBucketDetails; +use crate::remote_file_manager::remote_cloud_bucket_details::RemoteCloudBucketDetails; + pub struct FileBucketDirectory { file_object_hash: String, remote_cloud_base_directory: String, @@ -74,7 +75,6 @@ pub struct FileBucketDirectory { pub fn to_full_remote_cloud_file_path_pathbuf(&self) -> PathBuf { PathBuf::from(&self.full_remote_cloud_file_path) } - pub fn get_file_name(&self) -> &str { &self.file_name } diff --git a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/file_meta_data.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/file_meta_data.rs index a2fbfd5951..8066d28659 100644 --- a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/file_meta_data.rs +++ b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/file_meta_data.rs @@ -1,3 +1,4 @@ +#[derive(Debug, Clone)] pub struct FileMetaData { pub file_size_bytes: u64, pub sha256_checksum: String, diff --git a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/mod.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/mod.rs index 4bb18414b2..1bb4eac41f 100644 --- a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/mod.rs +++ b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/mod.rs @@ -1,7 +1,12 @@ pub mod remote_cloud_file_manager; +pub mod remote_cloud_bucket_details; + +pub mod bucket_orchestration; + + pub mod file_directory; pub mod file_meta_data; pub mod file_descriptor; pub mod media_descriptor; -pub mod weights_descriptor; \ No newline at end of file +pub mod weights_descriptor; diff --git a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_file_manager.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_file_manager.rs index ebb3b62e45..fa0bfee894 100644 --- a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_file_manager.rs +++ b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_file_manager.rs @@ -1,134 +1,79 @@ -use crate::bucket_client::BucketClient; + use crate::remote_file_manager::file_directory::FileBucketDirectory; +use crate::remote_file_manager::remote_cloud_bucket_details::RemoteCloudBucketDetails; + +use super::bucket_orchestration; use super::file_descriptor::{FileDescriptor, self}; use super::file_meta_data::FileMetaData; use std::time::Duration; -use anyhow::Ok; -use errors::{AnyhowError, AnyhowResult}; +use buckets::public::{public_path, self}; +use errors:: AnyhowResult; use filesys::file_read_bytes::file_read_bytes; use filesys::file_size::file_size; use filesys::path_to_string::path_to_string; use hashing::sha256::sha256_hash_file::sha256_hash_file; + use mimetypes::mimetype_for_bytes::get_mimetype_for_bytes; use mimetypes::mimetype_for_file::{get_mimetype_for_file, self}; -use s3::bucket; + + use log::info; +use storyteller_root::get_seed_tool_data_root; +use std::path::Path; -use super::weights_descriptor::{WeightsLoRADescriptor, WeightsSD15Descriptor, WeightsSDXLDescriptor, self}; - -// Takes the definition from database and is an input to enable us to download the file. -pub struct RemoteCloudBucketDetails { - object_hash: String, - prefix: String, - suffix: String, +use bucket_orchestration::BucketOrchestration; +struct RemoteCloudFileClient { + bucket_orchestration_client: BucketOrchestration } -impl RemoteCloudBucketDetails { - pub fn new(object_hash: String, prefix: String, suffix: String) -> Self { - Self { - object_hash: object_hash, - prefix: prefix, - suffix: suffix - } - } - pub fn get_object_hash(&self) -> &str { - &self.object_hash - } - pub fn get_prefix(&self) -> &str { - &self.prefix - } - pub fn get_suffix(&self) -> &str { - &self.suffix - } - - pub fn file_descriptor_from_bucket_details(&self) -> Box { - match self.prefix.as_str() { - "loRA" => Box::new(weights_descriptor::WeightsLoRADescriptor {}), - "SD15" => Box::new(weights_descriptor::WeightsSD15Descriptor {}), - "SDXL" => Box::new(weights_descriptor::WeightsSDXLDescriptor {}), - _ => panic!("Unknown prefix: {}", self.prefix) - } - } -} - -struct RemoteCloudFileClient {} - impl RemoteCloudFileClient { + pub fn new(bucket_orchestration_client: BucketOrchestration) -> Self { + Self { + bucket_orchestration_client: bucket_orchestration_client + } + } pub async fn download_file(&self, remote_cloud_bucket_details:RemoteCloudBucketDetails, to_system_file_path:String) -> AnyhowResult<()> { let file_descriptor = remote_cloud_bucket_details.file_descriptor_from_bucket_details(); let file_bucket_directory = FileBucketDirectory::from_existing_bucket_details(remote_cloud_bucket_details); - let full_remote_cloud_file_path = file_bucket_directory.get_full_remote_cloud_file_path(); - let bucket_client = self.get_bucket_with_visbility(file_descriptor.is_public()).await?; - bucket_client.download_file_to_disk(full_remote_cloud_file_path, to_system_file_path).await?; + let full_remote_cloud_file_path = file_bucket_directory.get_full_remote_cloud_file_path().to_string(); + let is_public = file_descriptor.is_public().clone(); + + self.bucket_orchestration_client.download_file_to_disk(full_remote_cloud_file_path, to_system_file_path, is_public).await?; Ok(()) } - pub async fn get_bucket_with_visbility(&self, public:bool) -> Result { - let access_key = easyenv::get_env_string_required("ACCESS_KEY")?; - let secret_key = easyenv::get_env_string_required("SECRET_KEY")?; - let region_name = easyenv::get_env_string_required("REGION_NAME")?; - let public_bucket_name = easyenv::get_env_string_required("PUBLIC_BUCKET_NAME")?; - let private_bucket_name = easyenv::get_env_string_required("PRIVATE_BUCKET_NAME")?; - - let bucket_timeout = easyenv::get_env_duration_seconds_or_default( - "BUCKET_TIMEOUT_SECONDS", Duration::from_secs(60 * 10)); - let mut bucket_client:BucketClient; - if public { - // use public bucket client - info!("Configuring public GCS bucket..."); - bucket_client = BucketClient::create( - &access_key, - &secret_key, - ®ion_name, - &public_bucket_name, - None, - Some(bucket_timeout), - )?; - } else { - info!("Configuring private GCS bucket..."); - bucket_client = BucketClient::create( - &access_key, - &secret_key, - ®ion_name, - &private_bucket_name, - None, - Some(bucket_timeout), - )?; - } - Ok(bucket_client) - } - // return error or success with meta data. - pub async fn upload_file(&self, file_descriptor:Box, from_system_file_path:&str) -> Result { - let bucket_client = self.get_bucket_with_visbility(file_descriptor.is_public()).await?; - + pub async fn upload_file(&self, file_descriptor:Box, from_system_file_path:&str) -> AnyhowResult { + // get file meta data - info!("Reading media file: {:?}", from_system_file_path); + println!("Reading media file: {:?}", from_system_file_path); // get meta data let bytes = file_read_bytes(from_system_file_path)?; - let result = Self::get_file_meta_data(from_system_file_path)?; + let is_public = file_descriptor.is_public(); let directory = FileBucketDirectory::generate_new( file_descriptor ); - - bucket_client.upload_file_with_content_type_process( + + println!("Uploading media file to bucket path: {:?}",directory.get_remote_cloud_base_directory()); + + self.bucket_orchestration_client.upload_file_with_content_type_process( &directory.get_remote_cloud_base_directory(), bytes.as_ref(), - result.mimetype.as_ref() + result.mimetype.as_ref(), + is_public ).await?; - Ok(result) } // Retrieve the metadata from the file - fn get_file_meta_data(system_file_path:&str) -> Result { + fn get_file_meta_data(system_file_path:&str) -> AnyhowResult { let file_size_bytes = file_size(system_file_path.clone())?; let sha256_checksum = sha256_hash_file(system_file_path.clone())?; @@ -145,11 +90,53 @@ impl RemoteCloudFileClient { #[cfg(test)] mod tests { - //use crate::public::files::file_descriptor::{FileDescriptor}; - //use super::RemoteCloudFileClient; - #[test] - fn test_web_file_manager() { + use env_logger; + use crate::remote_file_manager::weights_descriptor::{WeightsLoRADescriptor, WeightsSD15Descriptor, WeightsSDXLDescriptor}; + #[tokio::test] + async fn remote_file_manager_descriptor_test() { + use super::*; + let remote_cloud_bucket_details = RemoteCloudBucketDetails::new("object_hash".to_string(), "loRA".to_string(), "safetensors".to_string()); + let file_descriptor = remote_cloud_bucket_details.file_descriptor_from_bucket_details(); + + assert_eq!(file_descriptor.get_prefix(), "loRA"); + assert_eq!(file_descriptor.get_suffix(), "safetensors"); + assert_eq!(file_descriptor.is_public(), false); + } + #[tokio::test] + async fn remote_file_manager_download_existing_file() { + use super::*; + + //std::env::set_var(TEST_STORYTELLER_ROOT, "/testing/storyteller/root"); + + // assert_eq!(get_storyteller_root(), PathBuf::from("/testing/storyteller/root")); + // std::env::remove_var(TEST_STORYTELLER_ROOT); + // let access_key = easyenv::get_env_string_required("ACCESS_KEY")?; + // let secret_key = easyenv::get_env_string_required("SECRET_KEY")?; + // let region_name = easyenv::get_env_string_required("REGION_NAME")?; + // let public_bucket_name = easyenv::get_env_string_required("PUBLIC_BUCKET_NAME")?; + // let private_bucket_name = easyenv::get_env_string_required("PRIVATE_BUCKET_NAME")?; + + env_logger::init(); + + // let weight_path:&str= "models/imagegen/loRA/nijiMecha.safetensors"; + + // let seed_tool_data_root = get_seed_tool_data_root(); + // let weight_path = seed_tool_data_root.join(weight_path); + // let weight_path = weight_path.to_str().unwrap(); + + // println!("begin upload from weight_path: {:?}", weight_path); + // let result = remote_cloud_file_manager.upload_file(Box::new(WeightsLoRADescriptor {}),weight_path).await; + + // match result { + // Ok(file_meta_data) => { + // println!("file_meta_data: {:?}", file_meta_data); + // }, + // Err(e) => { + // println!("error: {:?}", e); + // } + // } + } } \ No newline at end of file diff --git a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/weights_descriptor.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/weights_descriptor.rs index b2a332ba7a..bccc6aee13 100644 --- a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/weights_descriptor.rs +++ b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/weights_descriptor.rs @@ -2,7 +2,6 @@ use super::file_descriptor::FileDescriptor; pub struct WeightsLoRADescriptor {} - const REMOTE_FILE_DIRECTORY: &str = "/weights"; impl FileDescriptor for WeightsLoRADescriptor { From 1bddb21e9f3a969747f30d8124898eeed7829243 Mon Sep 17 00:00:00 2001 From: Michael Chung Date: Thu, 21 Dec 2023 00:41:26 -0500 Subject: [PATCH 101/124] Missed 1 file. --- .../bucket_orchestration.rs | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 crates/lib/api_clients/cloud_storage/src/remote_file_manager/bucket_orchestration.rs diff --git a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/bucket_orchestration.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/bucket_orchestration.rs new file mode 100644 index 0000000000..e12c746e77 --- /dev/null +++ b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/bucket_orchestration.rs @@ -0,0 +1,112 @@ +use errors::AnyhowResult; +use crate::bucket_client::BucketClient; +use tokio::time::Duration; +use log::info; + +pub struct BucketOrchestration { + access_key: String, + secret_key: String, + region_name: String, + public_bucket_name: String, + private_bucket_name: String, +} + +impl BucketOrchestration { + pub fn new_bucket_client_from_existing_env()-> AnyhowResult { + + let access_key = easyenv::get_env_string_required("ACCESS_KEY")?; + let secret_key = easyenv::get_env_string_required("SECRET_KEY")?; + + let region_name = easyenv::get_env_string_required("REGION_NAME")?; + let public_bucket_name = easyenv::get_env_string_required("PUBLIC_BUCKET_NAME")?; + let private_bucket_name = easyenv::get_env_string_required("PRIVATE_BUCKET_NAME")?; + + + let bucket_orchestration = BucketOrchestration::new( + access_key, + secret_key, + region_name, + public_bucket_name, + private_bucket_name + ); + + Ok(bucket_orchestration) + } + + pub fn new( + access_key: String, + secret_key: String, + region_name: String, + public_bucket_name: String, + private_bucket_name: String) -> Self { + Self { + access_key: access_key, + secret_key: secret_key, + region_name: region_name, + public_bucket_name: public_bucket_name, + private_bucket_name: private_bucket_name, + } + } + + pub async fn download_file_to_disk( + &self, + object_path: String, + filesystem_path: String, + is_public:bool + ) -> AnyhowResult<()> { + let bucket_client = self.get_bucket_with_visbility(is_public).await?; + bucket_client.download_file_to_disk(object_path, filesystem_path).await + + } + + pub async fn upload_file_with_content_type_process(&self,object_name: &str, + bytes: &[u8], + content_type: &str, + is_public:bool) -> AnyhowResult<()> { + let bucket_client = self.get_bucket_with_visbility(is_public).await?; + bucket_client.upload_file_with_content_type_process( + object_name, + bytes, + content_type + ).await + + } + + async fn get_bucket_with_visbility(&self, public:bool) -> AnyhowResult { + + let bucket_timeout = easyenv::get_env_duration_seconds_or_default( + "BUCKET_TIMEOUT_SECONDS", Duration::from_secs(60 * 10)); + let bucket_client:BucketClient; + if public { + // use public bucket client + info!("Configuring public GCS bucket..."); + bucket_client = BucketClient::create( + &self.access_key, + &self.secret_key, + &self.region_name, + &self.public_bucket_name, + None, + Some(bucket_timeout), + )?; + } else { + info!("Configuring private GCS bucket..."); + bucket_client = BucketClient::create( + &self.access_key, + &self.secret_key, + &self.region_name, + &self.private_bucket_name, + None, + Some(bucket_timeout), + )?; + } + Ok(bucket_client) + } + +} + +#[cfg(test)] +mod tests { + + #[test] + pub fn test() {} +} \ No newline at end of file From eca8b01f140557d0f10fe46b030984e8cb86baf4 Mon Sep 17 00:00:00 2001 From: Michael Chung Date: Thu, 21 Dec 2023 00:42:22 -0500 Subject: [PATCH 102/124] Missed 1 file. --- .../remote_cloud_bucket_details.rs | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_bucket_details.rs diff --git a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_bucket_details.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_bucket_details.rs new file mode 100644 index 0000000000..39b9ada6b9 --- /dev/null +++ b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_bucket_details.rs @@ -0,0 +1,48 @@ + + +use super::file_descriptor::FileDescriptor; +use crate::remote_file_manager::weights_descriptor::{WeightsLoRADescriptor, WeightsSD15Descriptor, WeightsSDXLDescriptor, self}; + +pub struct RemoteCloudBucketDetails { + object_hash: String, + prefix: String, + suffix: String, +} + +impl RemoteCloudBucketDetails { + pub fn new(object_hash: String, prefix: String, suffix: String) -> Self { + Self { + object_hash: object_hash, + prefix: prefix, + suffix: suffix + } + } + pub fn get_object_hash(&self) -> &str { + &self.object_hash + } + pub fn get_prefix(&self) -> &str { + &self.prefix + } + pub fn get_suffix(&self) -> &str { + &self.suffix + } + + pub fn file_descriptor_from_bucket_details(&self) -> Box { + match self.prefix.as_str() { + "loRA" => Box::new(weights_descriptor::WeightsLoRADescriptor {}), + "SD15" => Box::new(weights_descriptor::WeightsSD15Descriptor {}), + "SDXL" => Box::new(weights_descriptor::WeightsSDXLDescriptor {}), + _ => panic!("Unknown prefix: {}", self.prefix) + } + } +} + + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + pub fn test() {} + +} \ No newline at end of file From 86c80fdf19fdd43be35edca9f272dbd1197ccc4f Mon Sep 17 00:00:00 2001 From: Michael Chung Date: Thu, 21 Dec 2023 01:01:35 -0500 Subject: [PATCH 103/124] Things build again editor works well. --- crates/lib/api_clients/cloud_storage/Cargo.toml | 4 ++-- crates/lib/api_clients/cloud_storage/src/bucket_client.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/lib/api_clients/cloud_storage/Cargo.toml b/crates/lib/api_clients/cloud_storage/Cargo.toml index 150adaaf58..3da8b27c71 100644 --- a/crates/lib/api_clients/cloud_storage/Cargo.toml +++ b/crates/lib/api_clients/cloud_storage/Cargo.toml @@ -22,14 +22,14 @@ easyenv = { path = "../../../lib/easyenv" } filesys = { path = "../../../lib/files/filesys" } hashing = { path = "../../../lib/files/hashing" } mimetypes = { path = "../../../lib/files/mimetypes" } - +storyteller_root = { path = "../../../lib/storyteller_root" } # Workspace hack (faster compile times) my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" } # External anyhow = "1.0.75" log = "0.4.14" - +env_logger = "0.10.1" # The "never-encode-slash" feature seems to have been removed: # https://github.com/durch/rust-s3/pull/254 rust-s3 = { version = "0.33.0" } diff --git a/crates/lib/api_clients/cloud_storage/src/bucket_client.rs b/crates/lib/api_clients/cloud_storage/src/bucket_client.rs index 577058cfd4..20ec855abb 100644 --- a/crates/lib/api_clients/cloud_storage/src/bucket_client.rs +++ b/crates/lib/api_clients/cloud_storage/src/bucket_client.rs @@ -121,7 +121,7 @@ impl BucketClient { } } - #[deprecated = "Use upload_file instead above it returns an error we can surface and act on."] + #[deprecated = "Use upload_file instead above it returns an error we can surface and act on. upload_file_with_content_type_process"] pub async fn upload_file_with_content_type(&self, object_name: &str, bytes: &[u8], content_type: &str) -> anyhow::Result<()> { info!("Filename for bucket: {}", object_name); From 0cff684e97373d51c13749753cac11210e407a72 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Thu, 21 Dec 2023 01:30:10 -0500 Subject: [PATCH 104/124] rename model_weights bucket fields: private -> public --- ...09d0eaaa2dd5797374b4c1aa103999e8e1542.json | 12 ---- ...1842076694c31cfc9336863638f829388727.json} | 10 +-- ...25a7727957b52b727831ce62518b3c5fc9bd.json} | 10 +-- ...8d4b99223761d4547ce7c8a9438ba92e8523.json} | 4 +- ...8a62ab5bba7cc5534469c3c061f9cfb0cd50.json} | 10 +-- ...752ce7892d76b56d2eff95db39c6b6d9f7f11.json | 12 ++++ ...15f6d2d023afe2bb31994d21a1007d81e0a0.json} | 10 +-- ...080c99e7930ec095c5600abb80a9d8c5154d.json} | 4 +- ...fcfef23422142735319c8cd091ca8179f97d.json} | 10 +-- .../down.sql | 12 ++++ .../up.sql | 12 ++++ .../model_weights/model_weights.sql | 12 ++-- .../src/seeding/model_weights.rs | 66 +++++++++---------- .../src/seeding/seed_model_weights.rs | 6 +- .../voice_conversion_to_weights/migrate.rs | 4 +- ...ight_from_voice_conversion_download_job.rs | 6 +- .../queries/model_weights/create_weight.rs | 18 ++--- .../src/queries/model_weights/get_weight.rs | 48 +++++++------- ...l_weight_for_voice_conversion_inference.rs | 18 ++--- .../model_weights/list_weights_by_tokens.rs | 36 +++++----- .../model_weights/list_weights_by_user.rs | 32 +++++---- .../list_weights_query_builder.rs | 26 ++++---- ...odel_weight_from_voice_conversion_model.rs | 15 ++--- .../queries/model_weights/table_reference.sql | 6 +- .../src/queries/model_weights/tests.rs | 36 +++++----- .../list_whole_tts_models_using_cursor.rs | 4 +- .../rerender_a_video/download_model_file.rs | 10 +-- 27 files changed, 232 insertions(+), 217 deletions(-) delete mode 100644 .sqlx/query-4f36ec7baa9fa98cca25b5cc11f09d0eaaa2dd5797374b4c1aa103999e8e1542.json rename .sqlx/{query-f0b5767d52c389660d1859e628c746f6f33a9e1c25f21f66aeeb0784df768c8e.json => query-7434b13f252c43b854e51c7761a71842076694c31cfc9336863638f829388727.json} (90%) rename .sqlx/{query-a6ed8524fb5339fed17bec6611f8f56b6bdee35bac63c9eacbe21eb032a6a831.json => query-854da1bad28fbcf5a8f82c26c52c25a7727957b52b727831ce62518b3c5fc9bd.json} (89%) rename .sqlx/{query-685839dd0d875409fc1f3262e234518760c3d5b10c46fb8daf96756746c01c81.json => query-8cb3ba5acb8dbef84408370810c98d4b99223761d4547ce7c8a9438ba92e8523.json} (57%) rename .sqlx/{query-6a94791c8a8f66ee54bb367a4e8c71106bbcbbb205f54c14e3657279e83dabb6.json => query-964cda4c4505907fd8af46b2f6578a62ab5bba7cc5534469c3c061f9cfb0cd50.json} (91%) create mode 100644 .sqlx/query-aae28dc5fbeff858e4c9dd8b079752ce7892d76b56d2eff95db39c6b6d9f7f11.json rename .sqlx/{query-0d4c43d9055cea3ce35c71ab8ef27058075414496dc5858d57a9f06d7c076bab.json => query-ae34c2ce11250786962be50f167f15f6d2d023afe2bb31994d21a1007d81e0a0.json} (83%) rename .sqlx/{query-274cfb1e3caca706e3dbc3d95064e0f4b354c936f8de948070854920f265cc41.json => query-cb07f1522d0d619e2f364af78250080c99e7930ec095c5600abb80a9d8c5154d.json} (61%) rename .sqlx/{query-3d586592422727dcc928574966bdf5081ac69fdbb856fffcbd68187fd99c4642.json => query-ec733ae6705dc03fb785e2299c35fcfef23422142735319c8cd091ca8179f97d.json} (90%) create mode 100644 _sql/migrations/2023-12-21-060916_alter_model_weights_rename_bucket_hash/down.sql create mode 100644 _sql/migrations/2023-12-21-060916_alter_model_weights_rename_bucket_hash/up.sql diff --git a/.sqlx/query-4f36ec7baa9fa98cca25b5cc11f09d0eaaa2dd5797374b4c1aa103999e8e1542.json b/.sqlx/query-4f36ec7baa9fa98cca25b5cc11f09d0eaaa2dd5797374b4c1aa103999e8e1542.json deleted file mode 100644 index 8d9012e798..0000000000 --- a/.sqlx/query-4f36ec7baa9fa98cca25b5cc11f09d0eaaa2dd5797374b4c1aa103999e8e1542.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "MySQL", - "query": "\nINSERT INTO model_weights\nSET\n token = ?,\n weights_type = ?,\n weights_category = ?,\n title = ?,\n maybe_thumbnail_token = NULL,\n maybe_avatar_media_file_token = NULL,\n maybe_cover_media_file_token = NULL,\n description_markdown = ?,\n description_rendered_html = ?,\n creator_user_token = ?,\n creator_ip_address = ?,\n\n creator_set_visibility = ?,\n maybe_last_update_user_token = NULL,\n original_download_url = ?,\n original_filename = ?,\n file_size_bytes = ?,\n file_checksum_sha2 = ?,\n\n private_bucket_hash = ?,\n maybe_private_bucket_prefix = ?,\n maybe_private_bucket_extension = ?,\n cached_user_ratings_total_count = 0,\n cached_user_ratings_positive_count = 0,\n cached_user_ratings_negative_count = 0,\n maybe_cached_user_ratings_ratio = 0.0,\n cached_user_ratings_last_updated_at = NOW(),\n\n maybe_migration_old_model_token = ?,\n version = ?,\n created_at = ?,\n updated_at = ?,\n user_deleted_at = ?,\n mod_deleted_at = ?\n\nON DUPLICATE KEY UPDATE\n weights_type = ?,\n weights_category = ?,\n title = ?,\n maybe_thumbnail_token = NULL,\n maybe_avatar_media_file_token = NULL,\n maybe_cover_media_file_token = NULL,\n description_markdown = ?,\n description_rendered_html = ?,\n creator_user_token = ?,\n creator_ip_address = ?,\n creator_set_visibility = ?,\n maybe_last_update_user_token = NULL,\n original_download_url = ?,\n original_filename = ?,\n file_size_bytes = ?,\n file_checksum_sha2 = ?,\n private_bucket_hash = ?,\n maybe_private_bucket_prefix = ?,\n maybe_private_bucket_extension = ?,\n cached_user_ratings_total_count = 0,\n cached_user_ratings_positive_count = 0,\n cached_user_ratings_negative_count = 0,\n maybe_cached_user_ratings_ratio = 0.0,\n cached_user_ratings_last_updated_at = NOW(),\n maybe_migration_old_model_token = ?,\n version = ?,\n created_at = ?,\n updated_at = ?,\n user_deleted_at = ?,\n mod_deleted_at = ?\n ", - "describe": { - "columns": [], - "parameters": { - "Right": 43 - }, - "nullable": [] - }, - "hash": "4f36ec7baa9fa98cca25b5cc11f09d0eaaa2dd5797374b4c1aa103999e8e1542" -} diff --git a/.sqlx/query-f0b5767d52c389660d1859e628c746f6f33a9e1c25f21f66aeeb0784df768c8e.json b/.sqlx/query-7434b13f252c43b854e51c7761a71842076694c31cfc9336863638f829388727.json similarity index 90% rename from .sqlx/query-f0b5767d52c389660d1859e628c746f6f33a9e1c25f21f66aeeb0784df768c8e.json rename to .sqlx/query-7434b13f252c43b854e51c7761a71842076694c31cfc9336863638f829388727.json index 440dfad3e0..45f8663bbd 100644 --- a/.sqlx/query-f0b5767d52c389660d1859e628c746f6f33a9e1c25f21f66aeeb0784df768c8e.json +++ b/.sqlx/query-7434b13f252c43b854e51c7761a71842076694c31cfc9336863638f829388727.json @@ -1,6 +1,6 @@ { "db_name": "MySQL", - "query": "\n SELECT\n wt.token as `token: tokens::tokens::model_weights::ModelWeightToken`,\n wt.title,\n wt.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n wt.weights_category as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n wt.maybe_thumbnail_token,\n wt.description_markdown,\n wt.description_rendered_html,\n wt.creator_user_token as `creator_user_token: tokens::tokens::users::UserToken`,\n wt.creator_ip_address,\n wt.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n wt.maybe_last_update_user_token as `maybe_last_update_user_token: tokens::tokens::users::UserToken`,\n wt.original_download_url,\n wt.original_filename,\n wt.file_size_bytes,\n wt.file_checksum_sha2,\n wt.private_bucket_hash,\n wt.maybe_private_bucket_prefix,\n wt.maybe_private_bucket_extension,\n wt.cached_user_ratings_negative_count,\n wt.cached_user_ratings_positive_count,\n wt.cached_user_ratings_total_count,\n wt.maybe_cached_user_ratings_ratio,\n wt.cached_user_ratings_last_updated_at,\n wt.version,\n wt.created_at,\n wt.updated_at,\n wt.user_deleted_at,\n wt.mod_deleted_at\n FROM model_weights as wt\n WHERE\n wt.token = ?\n AND wt.user_deleted_at IS NULL\n AND wt.mod_deleted_at IS NULL\n ", + "query": "\n SELECT\n wt.token as `token: tokens::tokens::model_weights::ModelWeightToken`,\n wt.title,\n wt.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n wt.weights_category as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n wt.maybe_thumbnail_token,\n wt.description_markdown,\n wt.description_rendered_html,\n wt.creator_user_token as `creator_user_token: tokens::tokens::users::UserToken`,\n wt.creator_ip_address,\n wt.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n wt.maybe_last_update_user_token as `maybe_last_update_user_token: tokens::tokens::users::UserToken`,\n wt.original_download_url,\n wt.original_filename,\n wt.file_size_bytes,\n wt.file_checksum_sha2,\n wt.public_bucket_hash,\n wt.maybe_public_bucket_prefix,\n wt.maybe_public_bucket_extension,\n wt.cached_user_ratings_negative_count,\n wt.cached_user_ratings_positive_count,\n wt.cached_user_ratings_total_count,\n wt.maybe_cached_user_ratings_ratio,\n wt.cached_user_ratings_last_updated_at,\n wt.version,\n wt.created_at,\n wt.updated_at,\n wt.user_deleted_at,\n wt.mod_deleted_at\n FROM model_weights as wt\n WHERE\n wt.token = ?\n AND wt.user_deleted_at IS NULL\n AND wt.mod_deleted_at IS NULL\n ", "describe": { "columns": [ { @@ -155,7 +155,7 @@ }, { "ordinal": 15, - "name": "private_bucket_hash", + "name": "public_bucket_hash", "type_info": { "type": "VarString", "flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE", @@ -165,7 +165,7 @@ }, { "ordinal": 16, - "name": "maybe_private_bucket_prefix", + "name": "maybe_public_bucket_prefix", "type_info": { "type": "VarString", "flags": "BINARY", @@ -175,7 +175,7 @@ }, { "ordinal": 17, - "name": "maybe_private_bucket_extension", + "name": "maybe_public_bucket_extension", "type_info": { "type": "VarString", "flags": "BINARY", @@ -318,5 +318,5 @@ true ] }, - "hash": "f0b5767d52c389660d1859e628c746f6f33a9e1c25f21f66aeeb0784df768c8e" + "hash": "7434b13f252c43b854e51c7761a71842076694c31cfc9336863638f829388727" } diff --git a/.sqlx/query-a6ed8524fb5339fed17bec6611f8f56b6bdee35bac63c9eacbe21eb032a6a831.json b/.sqlx/query-854da1bad28fbcf5a8f82c26c52c25a7727957b52b727831ce62518b3c5fc9bd.json similarity index 89% rename from .sqlx/query-a6ed8524fb5339fed17bec6611f8f56b6bdee35bac63c9eacbe21eb032a6a831.json rename to .sqlx/query-854da1bad28fbcf5a8f82c26c52c25a7727957b52b727831ce62518b3c5fc9bd.json index caa0eecbac..f63075f20d 100644 --- a/.sqlx/query-a6ed8524fb5339fed17bec6611f8f56b6bdee35bac63c9eacbe21eb032a6a831.json +++ b/.sqlx/query-854da1bad28fbcf5a8f82c26c52c25a7727957b52b727831ce62518b3c5fc9bd.json @@ -1,6 +1,6 @@ { "db_name": "MySQL", - "query": "\n SELECT\n mw.token as `token: tokens::tokens::model_weights::ModelWeightToken`,\n mw.title,\n mw.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n mw.weights_category as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n mw.maybe_thumbnail_token,\n mw.description_markdown,\n mw.description_rendered_html,\n users.token as `creator_user_token: tokens::tokens::users::UserToken`,\n users.username as creator_username,\n users.display_name as creator_display_name,\n users.email_gravatar_hash as creator_email_gravatar_hash,\n mw.creator_ip_address,\n mw.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n mw.maybe_last_update_user_token as `maybe_last_update_user_token: tokens::tokens::users::UserToken`,\n mw.original_download_url,\n mw.original_filename,\n mw.file_size_bytes,\n mw.file_checksum_sha2,\n mw.private_bucket_hash,\n mw.maybe_private_bucket_prefix,\n mw.maybe_private_bucket_extension,\n mw.cached_user_ratings_negative_count,\n mw.cached_user_ratings_positive_count,\n mw.cached_user_ratings_total_count,\n mw.maybe_cached_user_ratings_ratio,\n mw.cached_user_ratings_last_updated_at,\n mw.version,\n mw.created_at,\n mw.updated_at,\n mw.user_deleted_at,\n mw.mod_deleted_at\n FROM model_weights as mw\n JOIN users\n ON users.token = mw.creator_user_token\n WHERE\n users.username = ?\n AND mw.user_deleted_at IS NULL\n AND mw.mod_deleted_at IS NULL\n ", + "query": "\n SELECT\n mw.token as `token: tokens::tokens::model_weights::ModelWeightToken`,\n mw.title,\n mw.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n mw.weights_category as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n mw.maybe_thumbnail_token,\n mw.description_markdown,\n mw.description_rendered_html,\n users.token as `creator_user_token: tokens::tokens::users::UserToken`,\n users.username as creator_username,\n users.display_name as creator_display_name,\n users.email_gravatar_hash as creator_email_gravatar_hash,\n mw.creator_ip_address,\n mw.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n mw.maybe_last_update_user_token as `maybe_last_update_user_token: tokens::tokens::users::UserToken`,\n mw.original_download_url,\n mw.original_filename,\n mw.file_size_bytes,\n mw.file_checksum_sha2,\n mw.public_bucket_hash,\n mw.maybe_public_bucket_prefix,\n mw.maybe_public_bucket_extension,\n mw.cached_user_ratings_negative_count,\n mw.cached_user_ratings_positive_count,\n mw.cached_user_ratings_total_count,\n mw.maybe_cached_user_ratings_ratio,\n mw.cached_user_ratings_last_updated_at,\n mw.version,\n mw.created_at,\n mw.updated_at,\n mw.user_deleted_at,\n mw.mod_deleted_at\n FROM model_weights as mw\n JOIN users\n ON users.token = mw.creator_user_token\n WHERE\n users.username = ?\n AND mw.user_deleted_at IS NULL\n AND mw.mod_deleted_at IS NULL\n ", "describe": { "columns": [ { @@ -185,7 +185,7 @@ }, { "ordinal": 18, - "name": "private_bucket_hash", + "name": "public_bucket_hash", "type_info": { "type": "VarString", "flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE", @@ -195,7 +195,7 @@ }, { "ordinal": 19, - "name": "maybe_private_bucket_prefix", + "name": "maybe_public_bucket_prefix", "type_info": { "type": "VarString", "flags": "BINARY", @@ -205,7 +205,7 @@ }, { "ordinal": 20, - "name": "maybe_private_bucket_extension", + "name": "maybe_public_bucket_extension", "type_info": { "type": "VarString", "flags": "BINARY", @@ -351,5 +351,5 @@ true ] }, - "hash": "a6ed8524fb5339fed17bec6611f8f56b6bdee35bac63c9eacbe21eb032a6a831" + "hash": "854da1bad28fbcf5a8f82c26c52c25a7727957b52b727831ce62518b3c5fc9bd" } diff --git a/.sqlx/query-685839dd0d875409fc1f3262e234518760c3d5b10c46fb8daf96756746c01c81.json b/.sqlx/query-8cb3ba5acb8dbef84408370810c98d4b99223761d4547ce7c8a9438ba92e8523.json similarity index 57% rename from .sqlx/query-685839dd0d875409fc1f3262e234518760c3d5b10c46fb8daf96756746c01c81.json rename to .sqlx/query-8cb3ba5acb8dbef84408370810c98d4b99223761d4547ce7c8a9438ba92e8523.json index 0ddaa54cff..a64a581946 100644 --- a/.sqlx/query-685839dd0d875409fc1f3262e234518760c3d5b10c46fb8daf96756746c01c81.json +++ b/.sqlx/query-8cb3ba5acb8dbef84408370810c98d4b99223761d4547ce7c8a9438ba92e8523.json @@ -1,6 +1,6 @@ { "db_name": "MySQL", - "query": "\nINSERT INTO model_weights\nSET\n token = ?,\n weights_type = ?,\n weights_category = ?,\n title = ?,\n\n maybe_thumbnail_token = NULL,\n maybe_avatar_media_file_token = NULL,\n maybe_cover_media_file_token = NULL,\n description_markdown = NULL,\n description_rendered_html = NULL,\n\n maybe_last_update_user_token = NULL,\n original_download_url = ?,\n original_filename = ?,\n file_size_bytes = ?,\n file_checksum_sha2 = ?,\n\n creator_user_token = ?,\n creator_ip_address = ?,\n creator_set_visibility = ?,\n\n private_bucket_hash = ?,\n maybe_private_bucket_prefix = ?,\n maybe_private_bucket_extension = ?,\n\n cached_user_ratings_total_count = 0,\n cached_user_ratings_positive_count = 0,\n cached_user_ratings_negative_count = 0,\n maybe_cached_user_ratings_ratio = 0.0,\n cached_user_ratings_last_updated_at = NOW(),\n\n maybe_migration_old_model_token = ?\n ", + "query": "\nINSERT INTO model_weights\nSET\n token = ?,\n weights_type = ?,\n weights_category = ?,\n title = ?,\n\n maybe_thumbnail_token = NULL,\n maybe_avatar_media_file_token = NULL,\n maybe_cover_media_file_token = NULL,\n description_markdown = NULL,\n description_rendered_html = NULL,\n\n maybe_last_update_user_token = NULL,\n original_download_url = ?,\n original_filename = ?,\n file_size_bytes = ?,\n file_checksum_sha2 = ?,\n\n creator_user_token = ?,\n creator_ip_address = ?,\n creator_set_visibility = ?,\n\n public_bucket_hash = ?,\n maybe_public_bucket_prefix = ?,\n maybe_public_bucket_extension = ?,\n\n cached_user_ratings_total_count = 0,\n cached_user_ratings_positive_count = 0,\n cached_user_ratings_negative_count = 0,\n maybe_cached_user_ratings_ratio = 0.0,\n cached_user_ratings_last_updated_at = NOW(),\n\n maybe_migration_old_model_token = ?\n ", "describe": { "columns": [], "parameters": { @@ -8,5 +8,5 @@ }, "nullable": [] }, - "hash": "685839dd0d875409fc1f3262e234518760c3d5b10c46fb8daf96756746c01c81" + "hash": "8cb3ba5acb8dbef84408370810c98d4b99223761d4547ce7c8a9438ba92e8523" } diff --git a/.sqlx/query-6a94791c8a8f66ee54bb367a4e8c71106bbcbbb205f54c14e3657279e83dabb6.json b/.sqlx/query-964cda4c4505907fd8af46b2f6578a62ab5bba7cc5534469c3c061f9cfb0cd50.json similarity index 91% rename from .sqlx/query-6a94791c8a8f66ee54bb367a4e8c71106bbcbbb205f54c14e3657279e83dabb6.json rename to .sqlx/query-964cda4c4505907fd8af46b2f6578a62ab5bba7cc5534469c3c061f9cfb0cd50.json index a7108cdb5d..dc4967438c 100644 --- a/.sqlx/query-6a94791c8a8f66ee54bb367a4e8c71106bbcbbb205f54c14e3657279e83dabb6.json +++ b/.sqlx/query-964cda4c4505907fd8af46b2f6578a62ab5bba7cc5534469c3c061f9cfb0cd50.json @@ -1,6 +1,6 @@ { "db_name": "MySQL", - "query": "\n SELECT\n wt.token as `token: tokens::tokens::model_weights::ModelWeightToken`,\n wt.title,\n wt.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n wt.weights_category as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n wt.maybe_thumbnail_token,\n wt.description_markdown,\n wt.description_rendered_html,\n wt.creator_user_token as `creator_user_token: tokens::tokens::users::UserToken`,\n wt.creator_ip_address,\n wt.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n wt.maybe_last_update_user_token as `maybe_last_update_user_token: tokens::tokens::users::UserToken`,\n wt.original_download_url,\n wt.original_filename,\n wt.file_size_bytes,\n wt.file_checksum_sha2,\n wt.private_bucket_hash,\n wt.maybe_private_bucket_prefix,\n wt.maybe_private_bucket_extension,\n wt.cached_user_ratings_negative_count,\n wt.cached_user_ratings_positive_count,\n wt.cached_user_ratings_total_count,\n wt.maybe_cached_user_ratings_ratio,\n wt.cached_user_ratings_last_updated_at,\n wt.version,\n wt.created_at,\n wt.updated_at,\n wt.user_deleted_at,\n wt.mod_deleted_at\n FROM model_weights as wt\n WHERE\n wt.token = ?\n ", + "query": "\n SELECT\n wt.token as `token: tokens::tokens::model_weights::ModelWeightToken`,\n wt.title,\n wt.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n wt.weights_category as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n wt.maybe_thumbnail_token,\n wt.description_markdown,\n wt.description_rendered_html,\n wt.creator_user_token as `creator_user_token: tokens::tokens::users::UserToken`,\n wt.creator_ip_address,\n wt.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n wt.maybe_last_update_user_token as `maybe_last_update_user_token: tokens::tokens::users::UserToken`,\n wt.original_download_url,\n wt.original_filename,\n wt.file_size_bytes,\n wt.file_checksum_sha2,\n wt.public_bucket_hash,\n wt.maybe_public_bucket_prefix,\n wt.maybe_public_bucket_extension,\n wt.cached_user_ratings_negative_count,\n wt.cached_user_ratings_positive_count,\n wt.cached_user_ratings_total_count,\n wt.maybe_cached_user_ratings_ratio,\n wt.cached_user_ratings_last_updated_at,\n wt.version,\n wt.created_at,\n wt.updated_at,\n wt.user_deleted_at,\n wt.mod_deleted_at\n FROM model_weights as wt\n WHERE\n wt.token = ?\n ", "describe": { "columns": [ { @@ -155,7 +155,7 @@ }, { "ordinal": 15, - "name": "private_bucket_hash", + "name": "public_bucket_hash", "type_info": { "type": "VarString", "flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE", @@ -165,7 +165,7 @@ }, { "ordinal": 16, - "name": "maybe_private_bucket_prefix", + "name": "maybe_public_bucket_prefix", "type_info": { "type": "VarString", "flags": "BINARY", @@ -175,7 +175,7 @@ }, { "ordinal": 17, - "name": "maybe_private_bucket_extension", + "name": "maybe_public_bucket_extension", "type_info": { "type": "VarString", "flags": "BINARY", @@ -318,5 +318,5 @@ true ] }, - "hash": "6a94791c8a8f66ee54bb367a4e8c71106bbcbbb205f54c14e3657279e83dabb6" + "hash": "964cda4c4505907fd8af46b2f6578a62ab5bba7cc5534469c3c061f9cfb0cd50" } diff --git a/.sqlx/query-aae28dc5fbeff858e4c9dd8b079752ce7892d76b56d2eff95db39c6b6d9f7f11.json b/.sqlx/query-aae28dc5fbeff858e4c9dd8b079752ce7892d76b56d2eff95db39c6b6d9f7f11.json new file mode 100644 index 0000000000..d9db5ed2d0 --- /dev/null +++ b/.sqlx/query-aae28dc5fbeff858e4c9dd8b079752ce7892d76b56d2eff95db39c6b6d9f7f11.json @@ -0,0 +1,12 @@ +{ + "db_name": "MySQL", + "query": "\nINSERT INTO model_weights\nSET\n token = ?,\n weights_type = ?,\n weights_category = ?,\n title = ?,\n maybe_thumbnail_token = NULL,\n maybe_avatar_media_file_token = NULL,\n maybe_cover_media_file_token = NULL,\n description_markdown = ?,\n description_rendered_html = ?,\n creator_user_token = ?,\n creator_ip_address = ?,\n\n creator_set_visibility = ?,\n maybe_last_update_user_token = NULL,\n original_download_url = ?,\n original_filename = ?,\n file_size_bytes = ?,\n file_checksum_sha2 = ?,\n\n public_bucket_hash = ?,\n maybe_public_bucket_prefix = ?,\n maybe_public_bucket_extension = ?,\n cached_user_ratings_total_count = 0,\n cached_user_ratings_positive_count = 0,\n cached_user_ratings_negative_count = 0,\n maybe_cached_user_ratings_ratio = 0.0,\n cached_user_ratings_last_updated_at = NOW(),\n\n maybe_migration_old_model_token = ?,\n version = ?,\n created_at = ?,\n updated_at = ?,\n user_deleted_at = ?,\n mod_deleted_at = ?\n\nON DUPLICATE KEY UPDATE\n weights_type = ?,\n weights_category = ?,\n title = ?,\n maybe_thumbnail_token = NULL,\n maybe_avatar_media_file_token = NULL,\n maybe_cover_media_file_token = NULL,\n description_markdown = ?,\n description_rendered_html = ?,\n creator_user_token = ?,\n creator_ip_address = ?,\n creator_set_visibility = ?,\n maybe_last_update_user_token = NULL,\n original_download_url = ?,\n original_filename = ?,\n file_size_bytes = ?,\n file_checksum_sha2 = ?,\n public_bucket_hash = ?,\n maybe_public_bucket_prefix = ?,\n maybe_public_bucket_extension = ?,\n cached_user_ratings_total_count = 0,\n cached_user_ratings_positive_count = 0,\n cached_user_ratings_negative_count = 0,\n maybe_cached_user_ratings_ratio = 0.0,\n cached_user_ratings_last_updated_at = NOW(),\n maybe_migration_old_model_token = ?,\n version = ?,\n created_at = ?,\n updated_at = ?,\n user_deleted_at = ?,\n mod_deleted_at = ?\n ", + "describe": { + "columns": [], + "parameters": { + "Right": 43 + }, + "nullable": [] + }, + "hash": "aae28dc5fbeff858e4c9dd8b079752ce7892d76b56d2eff95db39c6b6d9f7f11" +} diff --git a/.sqlx/query-0d4c43d9055cea3ce35c71ab8ef27058075414496dc5858d57a9f06d7c076bab.json b/.sqlx/query-ae34c2ce11250786962be50f167f15f6d2d023afe2bb31994d21a1007d81e0a0.json similarity index 83% rename from .sqlx/query-0d4c43d9055cea3ce35c71ab8ef27058075414496dc5858d57a9f06d7c076bab.json rename to .sqlx/query-ae34c2ce11250786962be50f167f15f6d2d023afe2bb31994d21a1007d81e0a0.json index e6e8bbeced..d752df6337 100644 --- a/.sqlx/query-0d4c43d9055cea3ce35c71ab8ef27058075414496dc5858d57a9f06d7c076bab.json +++ b/.sqlx/query-ae34c2ce11250786962be50f167f15f6d2d023afe2bb31994d21a1007d81e0a0.json @@ -1,6 +1,6 @@ { "db_name": "MySQL", - "query": "\nSELECT\n w.token as `token: tokens::tokens::model_weights::ModelWeightToken`,\n w.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n\n w.title,\n vc.has_index_file,\n\n w.private_bucket_hash,\n w.maybe_private_bucket_prefix,\n w.maybe_private_bucket_extension,\n\n w.created_at,\n w.updated_at,\n w.user_deleted_at,\n w.mod_deleted_at\n\nFROM model_weights as w\nJOIN model_weights_extension_voice_conversion_details as vc\nON vc.model_weights_token = w.token\n\nWHERE w.token = ?\n ", + "query": "\nSELECT\n w.token as `token: tokens::tokens::model_weights::ModelWeightToken`,\n w.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n\n w.title,\n vc.has_index_file,\n\n w.public_bucket_hash,\n w.maybe_public_bucket_prefix,\n w.maybe_public_bucket_extension,\n\n w.created_at,\n w.updated_at,\n w.user_deleted_at,\n w.mod_deleted_at\n\nFROM model_weights as w\nJOIN model_weights_extension_voice_conversion_details as vc\nON vc.model_weights_token = w.token\n\nWHERE w.token = ?\n ", "describe": { "columns": [ { @@ -45,7 +45,7 @@ }, { "ordinal": 4, - "name": "private_bucket_hash", + "name": "public_bucket_hash", "type_info": { "type": "VarString", "flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE", @@ -55,7 +55,7 @@ }, { "ordinal": 5, - "name": "maybe_private_bucket_prefix", + "name": "maybe_public_bucket_prefix", "type_info": { "type": "VarString", "flags": "BINARY", @@ -65,7 +65,7 @@ }, { "ordinal": 6, - "name": "maybe_private_bucket_extension", + "name": "maybe_public_bucket_extension", "type_info": { "type": "VarString", "flags": "BINARY", @@ -131,5 +131,5 @@ true ] }, - "hash": "0d4c43d9055cea3ce35c71ab8ef27058075414496dc5858d57a9f06d7c076bab" + "hash": "ae34c2ce11250786962be50f167f15f6d2d023afe2bb31994d21a1007d81e0a0" } diff --git a/.sqlx/query-274cfb1e3caca706e3dbc3d95064e0f4b354c936f8de948070854920f265cc41.json b/.sqlx/query-cb07f1522d0d619e2f364af78250080c99e7930ec095c5600abb80a9d8c5154d.json similarity index 61% rename from .sqlx/query-274cfb1e3caca706e3dbc3d95064e0f4b354c936f8de948070854920f265cc41.json rename to .sqlx/query-cb07f1522d0d619e2f364af78250080c99e7930ec095c5600abb80a9d8c5154d.json index 415267c286..52e7c668e6 100644 --- a/.sqlx/query-274cfb1e3caca706e3dbc3d95064e0f4b354c936f8de948070854920f265cc41.json +++ b/.sqlx/query-cb07f1522d0d619e2f364af78250080c99e7930ec095c5600abb80a9d8c5154d.json @@ -1,6 +1,6 @@ { "db_name": "MySQL", - "query": "\n INSERT INTO model_weights\n SET\n token = ?,\n weights_type = ?,\n weights_category = ?,\n title = ?,\n maybe_thumbnail_token = ?,\n description_markdown = ?,\n description_rendered_html = ?,\n creator_user_token = ?,\n creator_ip_address = ?,\n creator_set_visibility = ?,\n maybe_last_update_user_token = ?,\n original_download_url = ?,\n original_filename = ?,\n file_size_bytes = ?,\n file_checksum_sha2 = ?,\n private_bucket_hash = ?,\n maybe_private_bucket_prefix = ?,\n maybe_private_bucket_extension = ?,\n cached_user_ratings_total_count = ?,\n cached_user_ratings_positive_count = ?,\n cached_user_ratings_negative_count = ?,\n maybe_cached_user_ratings_ratio = ?,\n version = ?\n ", + "query": "\n INSERT INTO model_weights\n SET\n token = ?,\n weights_type = ?,\n weights_category = ?,\n title = ?,\n maybe_thumbnail_token = ?,\n description_markdown = ?,\n description_rendered_html = ?,\n creator_user_token = ?,\n creator_ip_address = ?,\n creator_set_visibility = ?,\n maybe_last_update_user_token = ?,\n original_download_url = ?,\n original_filename = ?,\n file_size_bytes = ?,\n file_checksum_sha2 = ?,\n public_bucket_hash = ?,\n maybe_public_bucket_prefix = ?,\n maybe_public_bucket_extension = ?,\n cached_user_ratings_total_count = ?,\n cached_user_ratings_positive_count = ?,\n cached_user_ratings_negative_count = ?,\n maybe_cached_user_ratings_ratio = ?,\n version = ?\n ", "describe": { "columns": [], "parameters": { @@ -8,5 +8,5 @@ }, "nullable": [] }, - "hash": "274cfb1e3caca706e3dbc3d95064e0f4b354c936f8de948070854920f265cc41" + "hash": "cb07f1522d0d619e2f364af78250080c99e7930ec095c5600abb80a9d8c5154d" } diff --git a/.sqlx/query-3d586592422727dcc928574966bdf5081ac69fdbb856fffcbd68187fd99c4642.json b/.sqlx/query-ec733ae6705dc03fb785e2299c35fcfef23422142735319c8cd091ca8179f97d.json similarity index 90% rename from .sqlx/query-3d586592422727dcc928574966bdf5081ac69fdbb856fffcbd68187fd99c4642.json rename to .sqlx/query-ec733ae6705dc03fb785e2299c35fcfef23422142735319c8cd091ca8179f97d.json index 98ea6ac401..a8dbaee9e6 100644 --- a/.sqlx/query-3d586592422727dcc928574966bdf5081ac69fdbb856fffcbd68187fd99c4642.json +++ b/.sqlx/query-ec733ae6705dc03fb785e2299c35fcfef23422142735319c8cd091ca8179f97d.json @@ -1,6 +1,6 @@ { "db_name": "MySQL", - "query": "\n SELECT \n mw.token as `token: tokens::tokens::model_weights::ModelWeightToken`,\n mw.title,\n mw.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n mw.weights_category as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n mw.maybe_thumbnail_token,\n mw.description_markdown,\n mw.description_rendered_html,\n users.token as `creator_user_token: tokens::tokens::users::UserToken`,\n users.username as creator_username,\n users.display_name as creator_display_name,\n users.email_gravatar_hash as creator_email_gravatar_hash,\n mw.creator_ip_address,\n mw.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n mw.maybe_last_update_user_token as `maybe_last_update_user_token: tokens::tokens::users::UserToken`,\n mw.original_download_url,\n mw.original_filename,\n mw.file_size_bytes,\n mw.file_checksum_sha2,\n mw.private_bucket_hash,\n mw.maybe_private_bucket_prefix,\n mw.maybe_private_bucket_extension,\n mw.cached_user_ratings_negative_count,\n mw.cached_user_ratings_positive_count,\n mw.cached_user_ratings_total_count,\n mw.maybe_cached_user_ratings_ratio,\n mw.cached_user_ratings_last_updated_at,\n mw.version,\n mw.created_at,\n mw.updated_at,\n mw.user_deleted_at,\n mw.mod_deleted_at\n FROM model_weights as mw\n JOIN users\n ON users.token = mw.creator_user_token\n WHERE\n users.username = ?\n ", + "query": "\n SELECT \n mw.token as `token: tokens::tokens::model_weights::ModelWeightToken`,\n mw.title,\n mw.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n mw.weights_category as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n mw.maybe_thumbnail_token,\n mw.description_markdown,\n mw.description_rendered_html,\n users.token as `creator_user_token: tokens::tokens::users::UserToken`,\n users.username as creator_username,\n users.display_name as creator_display_name,\n users.email_gravatar_hash as creator_email_gravatar_hash,\n mw.creator_ip_address,\n mw.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n mw.maybe_last_update_user_token as `maybe_last_update_user_token: tokens::tokens::users::UserToken`,\n mw.original_download_url,\n mw.original_filename,\n mw.file_size_bytes,\n mw.file_checksum_sha2,\n mw.public_bucket_hash,\n mw.maybe_public_bucket_prefix,\n mw.maybe_public_bucket_extension,\n mw.cached_user_ratings_negative_count,\n mw.cached_user_ratings_positive_count,\n mw.cached_user_ratings_total_count,\n mw.maybe_cached_user_ratings_ratio,\n mw.cached_user_ratings_last_updated_at,\n mw.version,\n mw.created_at,\n mw.updated_at,\n mw.user_deleted_at,\n mw.mod_deleted_at\n FROM model_weights as mw\n JOIN users\n ON users.token = mw.creator_user_token\n WHERE\n users.username = ?\n ", "describe": { "columns": [ { @@ -185,7 +185,7 @@ }, { "ordinal": 18, - "name": "private_bucket_hash", + "name": "public_bucket_hash", "type_info": { "type": "VarString", "flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE", @@ -195,7 +195,7 @@ }, { "ordinal": 19, - "name": "maybe_private_bucket_prefix", + "name": "maybe_public_bucket_prefix", "type_info": { "type": "VarString", "flags": "BINARY", @@ -205,7 +205,7 @@ }, { "ordinal": 20, - "name": "maybe_private_bucket_extension", + "name": "maybe_public_bucket_extension", "type_info": { "type": "VarString", "flags": "BINARY", @@ -351,5 +351,5 @@ true ] }, - "hash": "3d586592422727dcc928574966bdf5081ac69fdbb856fffcbd68187fd99c4642" + "hash": "ec733ae6705dc03fb785e2299c35fcfef23422142735319c8cd091ca8179f97d" } diff --git a/_sql/migrations/2023-12-21-060916_alter_model_weights_rename_bucket_hash/down.sql b/_sql/migrations/2023-12-21-060916_alter_model_weights_rename_bucket_hash/down.sql new file mode 100644 index 0000000000..59b319f698 --- /dev/null +++ b/_sql/migrations/2023-12-21-060916_alter_model_weights_rename_bucket_hash/down.sql @@ -0,0 +1,12 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +ALTER TABLE model_weights + RENAME COLUMN public_bucket_hash TO private_bucket_hash; + +ALTER TABLE model_weights + RENAME COLUMN maybe_public_bucket_prefix TO maybe_private_bucket_prefix; + +ALTER TABLE model_weights + RENAME COLUMN maybe_public_bucket_extension TO maybe_private_bucket_extension; diff --git a/_sql/migrations/2023-12-21-060916_alter_model_weights_rename_bucket_hash/up.sql b/_sql/migrations/2023-12-21-060916_alter_model_weights_rename_bucket_hash/up.sql new file mode 100644 index 0000000000..f09a9927b2 --- /dev/null +++ b/_sql/migrations/2023-12-21-060916_alter_model_weights_rename_bucket_hash/up.sql @@ -0,0 +1,12 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +ALTER TABLE model_weights + RENAME COLUMN private_bucket_hash TO public_bucket_hash; + +ALTER TABLE model_weights + RENAME COLUMN maybe_private_bucket_prefix TO maybe_public_bucket_prefix; + +ALTER TABLE model_weights + RENAME COLUMN maybe_private_bucket_extension TO maybe_public_bucket_extension; diff --git a/_sql/migrations_squashed/model_weights/model_weights.sql b/_sql/migrations_squashed/model_weights/model_weights.sql index f17a5e1067..01171b0734 100644 --- a/_sql/migrations_squashed/model_weights/model_weights.sql +++ b/_sql/migrations_squashed/model_weights/model_weights.sql @@ -113,22 +113,22 @@ CREATE TABLE model_weights ( -- The hash for the bucket directory that contains the original upload -- as well as any associated other files. -- The bucket filename for the primary file (not including the directory path) is given by: - -- `[{maybe_private_bucket_prefix}]{private_bucket_hash}[{maybe_private_bucket_extension}]` - private_bucket_hash VARCHAR(32) NOT NULL, + -- `[{maybe_public_bucket_prefix}]{public_bucket_hash}[{maybe_public_bucket_extension}]` + public_bucket_hash VARCHAR(32) NOT NULL, -- An optional prefix on the bucket filename. -- If present, this will be prepended to the beginning of the bucket filename to access the file. -- The bucket filename for the primary file (not including the directory path) is given by: - -- `[{maybe_private_bucket_prefix}]{private_directory_hash}[{maybe_private_bucket_extension}]` - maybe_private_bucket_prefix VARCHAR(16) DEFAULT NULL, + -- `[{maybe_public_bucket_prefix}]{public_bucket_hash}[{maybe_public_bucket_extension}]` + maybe_public_bucket_prefix VARCHAR(16) DEFAULT NULL, -- An optional appended extension on the bucket filename. -- If present, this will be appended to the end of the bucket filename to access the file. -- To allow for flexibility, this extension typically will contain a leading period if -- the file needs it (eg ".mp4" rather than "mp4")! -- The bucket filename for the primary file (not including the directory path) is given by: - -- `[{maybe_private_bucket_prefix}]{private_directory_hash}[{maybe_private_bucket_extension}]` - maybe_private_bucket_extension VARCHAR(16) DEFAULT NULL, + -- `[{maybe_public_bucket_prefix}]{public_bucket_hash}[{maybe_public_bucket_extension}]` + maybe_public_bucket_extension VARCHAR(16) DEFAULT NULL, -- ========== MODERATION DETAILS ========== diff --git a/crates/cli/dev-database-seed/src/seeding/model_weights.rs b/crates/cli/dev-database-seed/src/seeding/model_weights.rs index 13e23d6014..96233496d5 100644 --- a/crates/cli/dev-database-seed/src/seeding/model_weights.rs +++ b/crates/cli/dev-database-seed/src/seeding/model_weights.rs @@ -335,9 +335,9 @@ pub async fn seed_weights_for_paging(mysql_pool: &Pool, user_token: UserT original_filename: Some(original_filename), file_size_bytes: 1024, file_checksum_sha2: "checksum1".to_string(), - private_bucket_hash: "bucket_hash1".to_string(), - maybe_private_bucket_prefix: Some(private_bucket_prefix), - maybe_private_bucket_extension: Some(private_bucket_extension), + public_bucket_hash: "bucket_hash1".to_string(), + maybe_public_bucket_prefix: Some(private_bucket_prefix), + maybe_public_bucket_extension: Some(private_bucket_extension), cached_user_ratings_total_count, cached_user_ratings_positive_count, cached_user_ratings_negative_count, @@ -381,9 +381,9 @@ pub async fn seed_weights_for_user_token( original_filename: Some("filename1.txt".to_string()), file_size_bytes: 1024, file_checksum_sha2: "checksum1".to_string(), - private_bucket_hash: "bucket_hash1".to_string(), - maybe_private_bucket_prefix: Some("_fake".to_string()), - maybe_private_bucket_extension: Some("rvc".to_string()), + public_bucket_hash: "bucket_hash1".to_string(), + maybe_public_bucket_prefix: Some("_fake".to_string()), + maybe_public_bucket_extension: Some("rvc".to_string()), cached_user_ratings_total_count: 10, cached_user_ratings_positive_count: 9, cached_user_ratings_negative_count: 1, @@ -407,9 +407,9 @@ pub async fn seed_weights_for_user_token( original_filename: Some("filename2.txt".to_string()), file_size_bytes: 2024, file_checksum_sha2: "checksum2".to_string(), - private_bucket_hash: "bucket_hash2".to_string(), - maybe_private_bucket_prefix: Some("_fake".to_string()), - maybe_private_bucket_extension: Some("tt2".to_string()), + public_bucket_hash: "bucket_hash2".to_string(), + maybe_public_bucket_prefix: Some("_fake".to_string()), + maybe_public_bucket_extension: Some("tt2".to_string()), cached_user_ratings_total_count: 20, cached_user_ratings_positive_count: 9, cached_user_ratings_negative_count: 2, @@ -433,9 +433,9 @@ pub async fn seed_weights_for_user_token( original_filename: Some("filename3.txt".to_string()), file_size_bytes: 3024, file_checksum_sha2: "checksum3".to_string(), - private_bucket_hash: "bucket_hash3".to_string(), - maybe_private_bucket_prefix: Some("_fake".to_string()), - maybe_private_bucket_extension: Some("safetensors".to_string()), + public_bucket_hash: "bucket_hash3".to_string(), + maybe_public_bucket_prefix: Some("_fake".to_string()), + maybe_public_bucket_extension: Some("safetensors".to_string()), cached_user_ratings_total_count: 10, cached_user_ratings_positive_count: 9, cached_user_ratings_negative_count: 1, @@ -459,9 +459,9 @@ pub async fn seed_weights_for_user_token( original_filename: Some("filename1.txt".to_string()), file_size_bytes: 1024, file_checksum_sha2: "checksum4".to_string(), - private_bucket_hash: "bucket_hash4".to_string(), - maybe_private_bucket_prefix: Some("_fake".to_string()), - maybe_private_bucket_extension: Some("LoRA".to_string()), + public_bucket_hash: "bucket_hash4".to_string(), + maybe_public_bucket_prefix: Some("_fake".to_string()), + maybe_public_bucket_extension: Some("LoRA".to_string()), cached_user_ratings_total_count: 10, cached_user_ratings_positive_count: 9, cached_user_ratings_negative_count: 1, @@ -485,9 +485,9 @@ pub async fn seed_weights_for_user_token( original_filename: Some("filename1.txt".to_string()), file_size_bytes: 1024, file_checksum_sha2: "checksum4".to_string(), - private_bucket_hash: "bucket_hash4".to_string(), - maybe_private_bucket_prefix: Some("_fake".to_string()), - maybe_private_bucket_extension: Some("LoRA".to_string()), + public_bucket_hash: "bucket_hash4".to_string(), + maybe_public_bucket_prefix: Some("_fake".to_string()), + maybe_public_bucket_extension: Some("LoRA".to_string()), cached_user_ratings_total_count: 10, cached_user_ratings_positive_count: 9, cached_user_ratings_negative_count: 1, @@ -537,9 +537,9 @@ pub async fn original_seed_weights(mysql_pool: &Pool,user_token: UserToke original_filename: Some("filename1.txt".to_string()), file_size_bytes: 1024, file_checksum_sha2: "checksum1".to_string(), - private_bucket_hash: "bucket_hash1".to_string(), - maybe_private_bucket_prefix: Some("_fake".to_string()), - maybe_private_bucket_extension: Some("rvc".to_string()), + public_bucket_hash: "bucket_hash1".to_string(), + maybe_public_bucket_prefix: Some("_fake".to_string()), + maybe_public_bucket_extension: Some("rvc".to_string()), cached_user_ratings_total_count: 10, cached_user_ratings_positive_count: 9, cached_user_ratings_negative_count: 1, @@ -563,9 +563,9 @@ pub async fn original_seed_weights(mysql_pool: &Pool,user_token: UserToke original_filename: Some("filename2.txt".to_string()), file_size_bytes: 2024, file_checksum_sha2: "checksum2".to_string(), - private_bucket_hash: "bucket_hash2".to_string(), - maybe_private_bucket_prefix: Some("_fake".to_string()), - maybe_private_bucket_extension: Some("tt2".to_string()), + public_bucket_hash: "bucket_hash2".to_string(), + maybe_public_bucket_prefix: Some("_fake".to_string()), + maybe_public_bucket_extension: Some("tt2".to_string()), cached_user_ratings_total_count: 20, cached_user_ratings_positive_count: 9, cached_user_ratings_negative_count: 2, @@ -589,9 +589,9 @@ pub async fn original_seed_weights(mysql_pool: &Pool,user_token: UserToke original_filename: Some("filename3.txt".to_string()), file_size_bytes: 3024, file_checksum_sha2: "checksum3".to_string(), - private_bucket_hash: "bucket_hash3".to_string(), - maybe_private_bucket_prefix: Some("_fake".to_string()), - maybe_private_bucket_extension: Some("safetensors".to_string()), + public_bucket_hash: "bucket_hash3".to_string(), + maybe_public_bucket_prefix: Some("_fake".to_string()), + maybe_public_bucket_extension: Some("safetensors".to_string()), cached_user_ratings_total_count: 10, cached_user_ratings_positive_count: 9, cached_user_ratings_negative_count: 1, @@ -615,9 +615,9 @@ pub async fn original_seed_weights(mysql_pool: &Pool,user_token: UserToke original_filename: Some("filename1.txt".to_string()), file_size_bytes: 1024, file_checksum_sha2: "checksum4".to_string(), - private_bucket_hash: "bucket_hash4".to_string(), - maybe_private_bucket_prefix: Some("_fake".to_string()), - maybe_private_bucket_extension: Some("LoRA".to_string()), + public_bucket_hash: "bucket_hash4".to_string(), + maybe_public_bucket_prefix: Some("_fake".to_string()), + maybe_public_bucket_extension: Some("LoRA".to_string()), cached_user_ratings_total_count: 10, cached_user_ratings_positive_count: 9, cached_user_ratings_negative_count: 1, @@ -641,9 +641,9 @@ pub async fn original_seed_weights(mysql_pool: &Pool,user_token: UserToke original_filename: Some("filename1.txt".to_string()), file_size_bytes: 1025, file_checksum_sha2: "checksum5".to_string(), - private_bucket_hash: "bucket_hash5".to_string(), - maybe_private_bucket_prefix: Some("_fake".to_string()), - maybe_private_bucket_extension: Some("LoRA".to_string()), + public_bucket_hash: "bucket_hash5".to_string(), + maybe_public_bucket_prefix: Some("_fake".to_string()), + maybe_public_bucket_extension: Some("LoRA".to_string()), cached_user_ratings_total_count: 10, cached_user_ratings_positive_count: 9, cached_user_ratings_negative_count: 1, diff --git a/crates/cli/dev-database-seed/src/seeding/seed_model_weights.rs b/crates/cli/dev-database-seed/src/seeding/seed_model_weights.rs index df11a86447..5f0bb838bb 100644 --- a/crates/cli/dev-database-seed/src/seeding/seed_model_weights.rs +++ b/crates/cli/dev-database-seed/src/seeding/seed_model_weights.rs @@ -141,9 +141,9 @@ pub async fn seed_weights_files( original_filename: Some(original_filename.to_string()), file_size_bytes: file_size_bytes as i32, // Assuming the file size is 0 file_checksum_sha2: sha256_checksum.to_string(), // Assuming the file checksum is an empty string - private_bucket_hash: bucket_hash, - maybe_private_bucket_prefix: Some(maybe_bucket_prefix.to_string()), - maybe_private_bucket_extension: Some(maybe_bucket_extension.to_string()), + public_bucket_hash: bucket_hash, + maybe_public_bucket_prefix: Some(maybe_bucket_prefix.to_string()), + maybe_public_bucket_extension: Some(maybe_bucket_extension.to_string()), cached_user_ratings_total_count, cached_user_ratings_positive_count, cached_user_ratings_negative_count, diff --git a/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/migrate.rs b/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/migrate.rs index 6c9beacc14..9c18763fa7 100644 --- a/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/migrate.rs +++ b/crates/cli/migration-tool/src/migrations/voice_conversion_to_weights/migrate.rs @@ -80,8 +80,8 @@ async fn lookup_bucket_details_from_record(model_weight_token: &ModelWeightToken }; let bucket_path = match model_weight_record.weights_type { - WeightsType::RvcV2 => WeightFileBucketPath::rvc_model_file_from_object_hash(&model_weight_record.private_bucket_hash), - WeightsType::SoVitsSvc => WeightFileBucketPath::svc_model_file_from_object_hash(&model_weight_record.private_bucket_hash), + WeightsType::RvcV2 => WeightFileBucketPath::rvc_model_file_from_object_hash(&model_weight_record.public_bucket_hash), + WeightsType::SoVitsSvc => WeightFileBucketPath::svc_model_file_from_object_hash(&model_weight_record.public_bucket_hash), _ => return Ok(None), // NB: Stable Diffusion, etc. aren't valid for migration }; diff --git a/crates/lib/mysql_queries/src/queries/model_weights/create/create_model_weight_from_voice_conversion_download_job.rs b/crates/lib/mysql_queries/src/queries/model_weights/create/create_model_weight_from_voice_conversion_download_job.rs index 3f5713c141..4ad5d6ce78 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/create/create_model_weight_from_voice_conversion_download_job.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/create/create_model_weight_from_voice_conversion_download_job.rs @@ -79,9 +79,9 @@ SET creator_ip_address = ?, creator_set_visibility = ?, - private_bucket_hash = ?, - maybe_private_bucket_prefix = ?, - maybe_private_bucket_extension = ?, + public_bucket_hash = ?, + maybe_public_bucket_prefix = ?, + maybe_public_bucket_extension = ?, cached_user_ratings_total_count = 0, cached_user_ratings_positive_count = 0, diff --git a/crates/lib/mysql_queries/src/queries/model_weights/create_weight.rs b/crates/lib/mysql_queries/src/queries/model_weights/create_weight.rs index 4827edd907..ee46eff6f4 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/create_weight.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/create_weight.rs @@ -24,9 +24,9 @@ pub struct CreateModelWeightsArgs<'a> { pub original_filename: Option, pub file_size_bytes: i32, pub file_checksum_sha2: String, - pub private_bucket_hash: String, - pub maybe_private_bucket_prefix: Option, - pub maybe_private_bucket_extension: Option, + pub public_bucket_hash: String, + pub maybe_public_bucket_prefix: Option, + pub maybe_public_bucket_extension: Option, pub cached_user_ratings_total_count: u32, pub cached_user_ratings_positive_count: u32, pub cached_user_ratings_negative_count: u32, @@ -58,9 +58,9 @@ pub async fn create_weight(args: CreateModelWeightsArgs<'_>) -> AnyhowResult) -> AnyhowResult, pub file_size_bytes: i32, pub file_checksum_sha2: String, - pub private_bucket_hash: String, - pub maybe_private_bucket_prefix: Option, // TODO crossproduct rename these to public thx ^-^ - pub maybe_private_bucket_extension: Option, + pub public_bucket_hash: String, + pub maybe_public_bucket_prefix: Option, + pub maybe_public_bucket_extension: Option, pub cached_user_ratings_negative_count: u32, pub cached_user_ratings_positive_count: u32, pub cached_user_ratings_total_count: u32, @@ -97,9 +95,9 @@ pub async fn get_weights_by_token_with_connection( original_filename: record.original_filename, file_size_bytes: record.file_size_bytes, file_checksum_sha2: record.file_checksum_sha2, - private_bucket_hash: record.private_bucket_hash, - maybe_private_bucket_prefix: record.maybe_private_bucket_prefix, - maybe_private_bucket_extension: record.maybe_private_bucket_extension, + public_bucket_hash: record.public_bucket_hash, + maybe_public_bucket_prefix: record.maybe_public_bucket_prefix, + maybe_public_bucket_extension: record.maybe_public_bucket_extension, cached_user_ratings_negative_count: record.cached_user_ratings_negative_count, cached_user_ratings_positive_count: record.cached_user_ratings_positive_count, cached_user_ratings_total_count: record.cached_user_ratings_total_count, @@ -138,9 +136,9 @@ async fn select_include_deleted( wt.original_filename, wt.file_size_bytes, wt.file_checksum_sha2, - wt.private_bucket_hash, - wt.maybe_private_bucket_prefix, - wt.maybe_private_bucket_extension, + wt.public_bucket_hash, + wt.maybe_public_bucket_prefix, + wt.maybe_public_bucket_extension, wt.cached_user_ratings_negative_count, wt.cached_user_ratings_positive_count, wt.cached_user_ratings_total_count, @@ -186,9 +184,9 @@ async fn select_without_deleted( wt.original_filename, wt.file_size_bytes, wt.file_checksum_sha2, - wt.private_bucket_hash, - wt.maybe_private_bucket_prefix, - wt.maybe_private_bucket_extension, + wt.public_bucket_hash, + wt.maybe_public_bucket_prefix, + wt.maybe_public_bucket_extension, wt.cached_user_ratings_negative_count, wt.cached_user_ratings_positive_count, wt.cached_user_ratings_total_count, @@ -228,9 +226,9 @@ pub struct RawWeight { pub original_filename: Option, pub file_size_bytes: i32, pub file_checksum_sha2: String, - pub private_bucket_hash: String, - pub maybe_private_bucket_prefix: Option, - pub maybe_private_bucket_extension: Option, + pub public_bucket_hash: String, + pub maybe_public_bucket_prefix: Option, + pub maybe_public_bucket_extension: Option, pub cached_user_ratings_negative_count: u32, pub cached_user_ratings_positive_count: u32, pub cached_user_ratings_total_count: u32, diff --git a/crates/lib/mysql_queries/src/queries/model_weights/inference/get_model_weight_for_voice_conversion_inference.rs b/crates/lib/mysql_queries/src/queries/model_weights/inference/get_model_weight_for_voice_conversion_inference.rs index eee49ee78f..cce98142e4 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/inference/get_model_weight_for_voice_conversion_inference.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/inference/get_model_weight_for_voice_conversion_inference.rs @@ -65,9 +65,9 @@ SELECT w.title, vc.has_index_file, - w.private_bucket_hash, - w.maybe_private_bucket_prefix, - w.maybe_private_bucket_extension, + w.public_bucket_hash, + w.maybe_public_bucket_prefix, + w.maybe_public_bucket_extension, w.created_at, w.updated_at, @@ -111,9 +111,9 @@ WHERE w.token = ? weights_type: model.weights_type, title: model.title, has_index_file: i8_to_bool(model.has_index_file), - public_bucket_hash: model.private_bucket_hash, - maybe_public_bucket_prefix: model.maybe_private_bucket_prefix, - maybe_public_bucket_extension: model.maybe_private_bucket_extension, + public_bucket_hash: model.public_bucket_hash, + maybe_public_bucket_prefix: model.maybe_public_bucket_prefix, + maybe_public_bucket_extension: model.maybe_public_bucket_extension, created_at: model.created_at, updated_at: model.updated_at, mod_deleted_at: model.mod_deleted_at, @@ -129,9 +129,9 @@ struct InternalRecord { has_index_file: i8, - private_bucket_hash: String, - maybe_private_bucket_prefix: Option, - maybe_private_bucket_extension: Option, + public_bucket_hash: String, + maybe_public_bucket_prefix: Option, + maybe_public_bucket_extension: Option, created_at: DateTime, updated_at: DateTime, diff --git a/crates/lib/mysql_queries/src/queries/model_weights/list_weights_by_tokens.rs b/crates/lib/mysql_queries/src/queries/model_weights/list_weights_by_tokens.rs index f08a9534a9..b1bb8fd980 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/list_weights_by_tokens.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/list_weights_by_tokens.rs @@ -27,9 +27,9 @@ pub struct WeightsByTokensRecord { pub creator_display_name: String, pub creator_email_gravatar_hash: String, - pub private_bucket_hash: String, - pub maybe_private_bucket_prefix: Option, - pub maybe_private_bucket_extension: Option, + pub public_bucket_hash: String, + pub maybe_public_bucket_prefix: Option, + pub maybe_public_bucket_extension: Option, pub cached_user_ratings_total_count: u32, pub cached_user_ratings_positive_count: u32, @@ -76,9 +76,9 @@ async fn get_raw_weights_by_tokens( users.username as creator_username, users.display_name as creator_display_name, users.email_gravatar_hash as creator_email_gravatar_hash, - mw.private_bucket_hash, - mw.maybe_private_bucket_prefix, - mw.maybe_private_bucket_extension, + mw.public_bucket_hash, + mw.maybe_public_bucket_prefix, + mw.maybe_public_bucket_extension, mw.cached_user_ratings_negative_count, mw.cached_user_ratings_positive_count, mw.cached_user_ratings_total_count, @@ -109,9 +109,9 @@ async fn get_raw_weights_by_tokens( users.username as creator_username, users.display_name as creator_display_name, users.email_gravatar_hash as creator_email_gravatar_hash, - mw.private_bucket_hash, - mw.maybe_private_bucket_prefix, - mw.maybe_private_bucket_extension, + mw.public_bucket_hash, + mw.maybe_public_bucket_prefix, + mw.maybe_public_bucket_extension, mw.cached_user_ratings_negative_count, mw.cached_user_ratings_positive_count, mw.cached_user_ratings_total_count, @@ -170,9 +170,9 @@ fn map_to_weights(dataset:Vec) -> Vec creator_display_name:dataset.creator_display_name, creator_email_gravatar_hash:dataset.creator_email_gravatar_hash, - private_bucket_hash: dataset.private_bucket_hash, - maybe_private_bucket_prefix: dataset.maybe_private_bucket_prefix, - maybe_private_bucket_extension: dataset.maybe_private_bucket_extension, + public_bucket_hash: dataset.public_bucket_hash, + maybe_public_bucket_prefix: dataset.maybe_public_bucket_prefix, + maybe_public_bucket_extension: dataset.maybe_public_bucket_extension, cached_user_ratings_negative_count: dataset.cached_user_ratings_negative_count, cached_user_ratings_positive_count: dataset.cached_user_ratings_positive_count, @@ -207,9 +207,9 @@ fn map_to_weights(dataset:Vec) -> Vec pub creator_display_name: String, pub creator_email_gravatar_hash: String, - pub private_bucket_hash: String, - pub maybe_private_bucket_prefix: Option, - pub maybe_private_bucket_extension: Option, + pub public_bucket_hash: String, + pub maybe_public_bucket_prefix: Option, + pub maybe_public_bucket_extension: Option, pub cached_user_ratings_total_count: u32, pub cached_user_ratings_positive_count: u32, @@ -247,9 +247,9 @@ impl FromRow<'_, MySqlRow> for RawWeightJoinUser { creator_username: row.try_get("creator_username")?, creator_display_name: row.try_get("creator_display_name")?, creator_email_gravatar_hash: row.try_get("creator_email_gravatar_hash")?, - private_bucket_hash: row.try_get("private_bucket_hash")?, - maybe_private_bucket_prefix: row.try_get("maybe_private_bucket_prefix")?, - maybe_private_bucket_extension: row.try_get("maybe_private_bucket_extension")?, + public_bucket_hash: row.try_get("public_bucket_hash")?, + maybe_public_bucket_prefix: row.try_get("maybe_public_bucket_prefix")?, + maybe_public_bucket_extension: row.try_get("maybe_public_bucket_extension")?, cached_user_ratings_total_count: row.try_get("cached_user_ratings_total_count")?, cached_user_ratings_positive_count: row.try_get("cached_user_ratings_positive_count")?, cached_user_ratings_negative_count: row.try_get("cached_user_ratings_negative_count")?, diff --git a/crates/lib/mysql_queries/src/queries/model_weights/list_weights_by_user.rs b/crates/lib/mysql_queries/src/queries/model_weights/list_weights_by_user.rs index 158e529649..3d069b1a09 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/list_weights_by_user.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/list_weights_by_user.rs @@ -36,10 +36,9 @@ pub struct WeightsJoinUserRecord { pub file_size_bytes: i32, pub file_checksum_sha2: String, - pub private_bucket_hash: String, - - pub maybe_private_bucket_prefix: Option, - pub maybe_private_bucket_extension: Option, + pub public_bucket_hash: String, + pub maybe_public_bucket_prefix: Option, + pub maybe_public_bucket_extension: Option, pub cached_user_ratings_total_count: u32, pub cached_user_ratings_positive_count: u32, @@ -105,9 +104,9 @@ async fn get_raw_weights_by_creator_username( mw.original_filename, mw.file_size_bytes, mw.file_checksum_sha2, - mw.private_bucket_hash, - mw.maybe_private_bucket_prefix, - mw.maybe_private_bucket_extension, + mw.public_bucket_hash, + mw.maybe_public_bucket_prefix, + mw.maybe_public_bucket_extension, mw.cached_user_ratings_negative_count, mw.cached_user_ratings_positive_count, mw.cached_user_ratings_total_count, @@ -150,9 +149,9 @@ async fn get_raw_weights_by_creator_username( mw.original_filename, mw.file_size_bytes, mw.file_checksum_sha2, - mw.private_bucket_hash, - mw.maybe_private_bucket_prefix, - mw.maybe_private_bucket_extension, + mw.public_bucket_hash, + mw.maybe_public_bucket_prefix, + mw.maybe_public_bucket_extension, mw.cached_user_ratings_negative_count, mw.cached_user_ratings_positive_count, mw.cached_user_ratings_total_count, @@ -199,9 +198,9 @@ async fn map_to_weights(dataset:Vec) -> Vec) -> Vec, - pub maybe_private_bucket_extension: Option, + pub public_bucket_hash: String, + pub maybe_public_bucket_prefix: Option, + pub maybe_public_bucket_extension: Option, pub cached_user_ratings_total_count: u32, pub cached_user_ratings_positive_count: u32, diff --git a/crates/lib/mysql_queries/src/queries/model_weights/list_weights_query_builder.rs b/crates/lib/mysql_queries/src/queries/model_weights/list_weights_query_builder.rs index d1d18302b9..078ed937ed 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/list_weights_query_builder.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/list_weights_query_builder.rs @@ -55,10 +55,9 @@ pub struct WeightJoinUser { pub file_size_bytes: i32, pub file_checksum_sha2: String, - pub private_bucket_hash: String, - - pub maybe_private_bucket_prefix: Option, - pub maybe_private_bucket_extension: Option, + pub public_bucket_hash: String, + pub maybe_public_bucket_prefix: Option, + pub maybe_public_bucket_extension: Option, pub cached_user_ratings_total_count: u32, pub cached_user_ratings_positive_count: u32, @@ -234,9 +233,9 @@ impl ListWeightsQueryBuilder { original_filename: record.original_filename, file_size_bytes: record.file_size_bytes, file_checksum_sha2: record.file_checksum_sha2, - private_bucket_hash: record.private_bucket_hash, - maybe_private_bucket_prefix: record.maybe_private_bucket_prefix, - maybe_private_bucket_extension: record.maybe_private_bucket_extension, + public_bucket_hash: record.public_bucket_hash, + maybe_public_bucket_prefix: record.maybe_public_bucket_prefix, + maybe_public_bucket_extension: record.maybe_public_bucket_extension, cached_user_ratings_total_count: record.cached_user_ratings_total_count, cached_user_ratings_positive_count: record.cached_user_ratings_positive_count, cached_user_ratings_negative_count: record.cached_user_ratings_negative_count, @@ -282,9 +281,9 @@ impl ListWeightsQueryBuilder { model_weights.original_filename, model_weights.file_size_bytes, model_weights.file_checksum_sha2, - model_weights.private_bucket_hash, - model_weights.maybe_private_bucket_prefix, - model_weights.maybe_private_bucket_extension, + model_weights.public_bucket_hash, + model_weights.maybe_public_bucket_prefix, + model_weights.maybe_public_bucket_extension, model_weights.cached_user_ratings_total_count, model_weights.cached_user_ratings_positive_count, model_weights.cached_user_ratings_negative_count, @@ -442,10 +441,9 @@ struct RawWeightJoinUser { pub file_size_bytes: i32, pub file_checksum_sha2: String, - pub private_bucket_hash: String, - - pub maybe_private_bucket_prefix: Option, - pub maybe_private_bucket_extension: Option, + pub public_bucket_hash: String, + pub maybe_public_bucket_prefix: Option, + pub maybe_public_bucket_extension: Option, pub cached_user_ratings_total_count: u32, pub cached_user_ratings_positive_count: u32, diff --git a/crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs b/crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs index 76799a629c..c590a45d21 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/migration/upsert_model_weight_from_voice_conversion_model.rs @@ -63,9 +63,8 @@ pub async fn upsert_model_weights_record( // NB: Not setting a few fields (for now) // maybe_last_update_user_token - seems like bad design - // TODO(bt): OBVIOUSLY COPY THE BUCKET FILES ! // TODO(bt): file checksum - // TODO(bt): rename maybe_private_bucket_extension to maybe_private_bucket_suffix (!!!) + // TODO(bt): rename maybe_public_bucket_extension to maybe_public_bucket_suffix (!!!) // TODO(bt): do we need model_weights.ip_address_last_update without audit logs? // TODO(bt): rename creator_ip_address to ip_address_creation (and add ip_address_last_update) // TODO(bt): Check model_weights column integer types - signed vs unsigned @@ -92,9 +91,9 @@ SET file_size_bytes = ?, file_checksum_sha2 = ?, - private_bucket_hash = ?, - maybe_private_bucket_prefix = ?, - maybe_private_bucket_extension = ?, + public_bucket_hash = ?, + maybe_public_bucket_prefix = ?, + maybe_public_bucket_extension = ?, cached_user_ratings_total_count = 0, cached_user_ratings_positive_count = 0, cached_user_ratings_negative_count = 0, @@ -125,9 +124,9 @@ ON DUPLICATE KEY UPDATE original_filename = ?, file_size_bytes = ?, file_checksum_sha2 = ?, - private_bucket_hash = ?, - maybe_private_bucket_prefix = ?, - maybe_private_bucket_extension = ?, + public_bucket_hash = ?, + maybe_public_bucket_prefix = ?, + maybe_public_bucket_extension = ?, cached_user_ratings_total_count = 0, cached_user_ratings_positive_count = 0, cached_user_ratings_negative_count = 0, diff --git a/crates/lib/mysql_queries/src/queries/model_weights/table_reference.sql b/crates/lib/mysql_queries/src/queries/model_weights/table_reference.sql index edd6e7407b..ad0cdbdf75 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/table_reference.sql +++ b/crates/lib/mysql_queries/src/queries/model_weights/table_reference.sql @@ -19,9 +19,9 @@ CREATE TABLE model_weights ( original_filename VARCHAR(255) DEFAULT NULL, file_size_bytes INT(10) NOT NULL DEFAULT 0, file_checksum_sha2 CHAR(64) NOT NULL, - private_bucket_hash VARCHAR(32) NOT NULL, - maybe_private_bucket_prefix VARCHAR(16) DEFAULT NULL, - maybe_private_bucket_extension VARCHAR(16) DEFAULT NULL, + public_bucket_hash VARCHAR(32) NOT NULL, + maybe_public_bucket_prefix VARCHAR(16) DEFAULT NULL, + maybe_public_bucket_extension VARCHAR(16) DEFAULT NULL, cached_user_ratings_total_count INT(10) UNSIGNED NOT NULL DEFAULT 0, cached_user_ratings_positive_count INT(10) UNSIGNED NOT NULL DEFAULT 0, cached_user_ratings_negative_count INT(10) UNSIGNED NOT NULL DEFAULT 0, diff --git a/crates/lib/mysql_queries/src/queries/model_weights/tests.rs b/crates/lib/mysql_queries/src/queries/model_weights/tests.rs index 3239e4173e..aae8a097fb 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/tests.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/tests.rs @@ -76,9 +76,9 @@ mod tests { original_filename: Some("filename1.txt".to_string()), file_size_bytes: 1024, file_checksum_sha2: "checksum1".to_string(), - private_bucket_hash: "bucket_hash1".to_string(), - maybe_private_bucket_prefix: Some("_fake".to_string()), - maybe_private_bucket_extension: Some("rvc".to_string()), + public_bucket_hash: "bucket_hash1".to_string(), + maybe_public_bucket_prefix: Some("_fake".to_string()), + maybe_public_bucket_extension: Some("rvc".to_string()), cached_user_ratings_total_count: 10, cached_user_ratings_positive_count: 9, cached_user_ratings_negative_count: 1, @@ -112,9 +112,9 @@ mod tests { assert_eq!(result.original_filename, Some("filename1.txt".to_string())); assert_eq!(result.file_size_bytes, 1024); assert_eq!(result.file_checksum_sha2, "checksum1".to_string()); - assert_eq!(result.private_bucket_hash, "bucket_hash1".to_string()); - assert_eq!(result.maybe_private_bucket_prefix, Some("_fake".to_string())); - assert_eq!(result.maybe_private_bucket_extension, Some("rvc".to_string())); + assert_eq!(result.public_bucket_hash, "bucket_hash1".to_string()); + assert_eq!(result.maybe_public_bucket_prefix, Some("_fake".to_string())); + assert_eq!(result.maybe_public_bucket_extension, Some("rvc".to_string())); assert_eq!(result.cached_user_ratings_total_count, 10); assert_eq!(result.cached_user_ratings_positive_count, 9); assert_eq!(result.cached_user_ratings_negative_count, 1); @@ -151,9 +151,9 @@ mod tests { original_filename: Some("filename1.txt".to_string()), file_size_bytes: 1024, file_checksum_sha2: "checksum1".to_string(), - private_bucket_hash: "bucket_hash1".to_string(), - maybe_private_bucket_prefix: Some("_fake".to_string()), - maybe_private_bucket_extension: Some("rvc".to_string()), + public_bucket_hash: "bucket_hash1".to_string(), + maybe_public_bucket_prefix: Some("_fake".to_string()), + maybe_public_bucket_extension: Some("rvc".to_string()), cached_user_ratings_total_count: 10, cached_user_ratings_positive_count: 9, cached_user_ratings_negative_count: 1, @@ -228,9 +228,9 @@ mod tests { original_filename: Some("filename1.txt".to_string()), file_size_bytes: 1024, file_checksum_sha2: "checksum1".to_string(), - private_bucket_hash: "bucket_hash1".to_string(), - maybe_private_bucket_prefix: Some("_fake".to_string()), - maybe_private_bucket_extension: Some("rvc".to_string()), + public_bucket_hash: "bucket_hash1".to_string(), + maybe_public_bucket_prefix: Some("_fake".to_string()), + maybe_public_bucket_extension: Some("rvc".to_string()), cached_user_ratings_total_count: 10, cached_user_ratings_positive_count: 9, cached_user_ratings_negative_count: 1, @@ -340,9 +340,9 @@ mod tests { original_filename: Some(format!("filename {}.txt", i)), file_size_bytes: 1024, file_checksum_sha2: format!("checksum{}", i), - private_bucket_hash: format!("bucket_hash{}", i), - maybe_private_bucket_prefix: Some("_fake".to_string()), - maybe_private_bucket_extension: Some("rvc".to_string()), + public_bucket_hash: format!("bucket_hash{}", i), + maybe_public_bucket_prefix: Some("_fake".to_string()), + maybe_public_bucket_extension: Some("rvc".to_string()), cached_user_ratings_total_count: 10, cached_user_ratings_positive_count: 9, cached_user_ratings_negative_count: 1, @@ -583,9 +583,9 @@ mod tests { original_filename: Some(format!("filename {}.txt", i)), file_size_bytes: 1024, file_checksum_sha2: format!("checksum{}", i), - private_bucket_hash: format!("bucket_hash{}", i), - maybe_private_bucket_prefix: Some("_fake".to_string()), - maybe_private_bucket_extension: Some("rvc".to_string()), + public_bucket_hash: format!("bucket_hash{}", i), + maybe_public_bucket_prefix: Some("_fake".to_string()), + maybe_public_bucket_extension: Some("rvc".to_string()), cached_user_ratings_total_count: 10, cached_user_ratings_positive_count: 9, cached_user_ratings_negative_count: 1, diff --git a/crates/lib/mysql_queries/src/queries/tts/tts_models/migration/list_whole_tts_models_using_cursor.rs b/crates/lib/mysql_queries/src/queries/tts/tts_models/migration/list_whole_tts_models_using_cursor.rs index b40243f612..af25d2adc2 100644 --- a/crates/lib/mysql_queries/src/queries/tts/tts_models/migration/list_whole_tts_models_using_cursor.rs +++ b/crates/lib/mysql_queries/src/queries/tts/tts_models/migration/list_whole_tts_models_using_cursor.rs @@ -3,16 +3,14 @@ use chrono::{DateTime, Utc}; use log::warn; use sqlx::{MySql, MySqlPool}; use sqlx::pool::PoolConnection; -use enums::by_table::tts_models::tts_model_type::TtsModelType; -use enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType; +use enums::by_table::tts_models::tts_model_type::TtsModelType; use enums::common::visibility::Visibility; use errors::AnyhowResult; use tokens::tokens::model_weights::ModelWeightToken; use tokens::tokens::tts_models::TtsModelToken; use tokens::tokens::users::UserToken; use tokens::tokens::vocoder_models::VocoderModelToken; -use tokens::tokens::voice_conversion_models::VoiceConversionModelToken; use crate::helpers::boolean_converters::{i8_to_bool, nullable_i8_to_optional_bool}; diff --git a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/download_model_file.rs b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/download_model_file.rs index 295d9a1ad0..63e434beff 100644 --- a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/download_model_file.rs +++ b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/download_model_file.rs @@ -32,12 +32,12 @@ pub async fn download_model_file( Some(model_record) => { let model_bucket_path = MediaFileBucketPath::from_object_hash( - &model_record.private_bucket_hash, - model_record.maybe_private_bucket_prefix.as_deref(), - model_record.maybe_private_bucket_extension.as_deref(), + &model_record.public_bucket_hash, + model_record.maybe_public_bucket_prefix.as_deref(), + model_record.maybe_public_bucket_extension.as_deref(), ); - let base_name = &model_record.private_bucket_hash; - let extension = model_record.maybe_private_bucket_extension.as_deref().unwrap_or("bin"); + let base_name = &model_record.public_bucket_hash; + let extension = model_record.maybe_public_bucket_extension.as_deref().unwrap_or("bin"); model_filename = format!("{base_name}.{extension}"); bucket_object_path = model_bucket_path.to_full_object_pathbuf(); } From 6b2d4ffdcea68fd21d489178f5ffa3a7c4e2eb25 Mon Sep 17 00:00:00 2001 From: Michael Chung Date: Thu, 21 Dec 2023 01:58:43 -0500 Subject: [PATCH 105/124] Adding the mocks --- .../lib/api_clients/cloud_storage/Cargo.toml | 2 + .../lib/api_clients/cloud_storage/src/lib.rs | 3 +- .../bucket_orchestration.rs | 75 ++++++++++----- .../remote_cloud_bucket_details.rs | 13 ++- .../remote_file_manager/weights_descriptor.rs | 96 +++++++++++++++++++ .../bucket_orchestration_mock.rs | 5 + .../src/remote_file_manager_mock/mod.rs | 1 + 7 files changed, 168 insertions(+), 27 deletions(-) create mode 100644 crates/lib/api_clients/cloud_storage/src/remote_file_manager_mock/bucket_orchestration_mock.rs create mode 100644 crates/lib/api_clients/cloud_storage/src/remote_file_manager_mock/mod.rs diff --git a/crates/lib/api_clients/cloud_storage/Cargo.toml b/crates/lib/api_clients/cloud_storage/Cargo.toml index 3da8b27c71..86a3de927e 100644 --- a/crates/lib/api_clients/cloud_storage/Cargo.toml +++ b/crates/lib/api_clients/cloud_storage/Cargo.toml @@ -30,6 +30,8 @@ my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" } anyhow = "1.0.75" log = "0.4.14" env_logger = "0.10.1" +async-trait = "0.1.58" + # The "never-encode-slash" feature seems to have been removed: # https://github.com/durch/rust-s3/pull/254 rust-s3 = { version = "0.33.0" } diff --git a/crates/lib/api_clients/cloud_storage/src/lib.rs b/crates/lib/api_clients/cloud_storage/src/lib.rs index da2cb76964..47b8b2ac76 100644 --- a/crates/lib/api_clients/cloud_storage/src/lib.rs +++ b/crates/lib/api_clients/cloud_storage/src/lib.rs @@ -1,3 +1,4 @@ pub mod bucket_client; pub mod bucket_path_unifier; -pub mod remote_file_manager; \ No newline at end of file +pub mod remote_file_manager; +pub mod remote_file_manager_mock; \ No newline at end of file diff --git a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/bucket_orchestration.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/bucket_orchestration.rs index e12c746e77..4d071769f0 100644 --- a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/bucket_orchestration.rs +++ b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/bucket_orchestration.rs @@ -2,6 +2,27 @@ use errors::AnyhowResult; use crate::bucket_client::BucketClient; use tokio::time::Duration; use log::info; +use crate::remote_file_manager_mock::bucket_orchestration_mock; +use async_trait::async_trait; +#[async_trait] +pub trait BucketOrchestrationDownload { + async fn download_file_to_disk( + &self, + object_path: String, + filesystem_path: String, + is_public:bool + ) -> AnyhowResult<()>; +} + +#[async_trait] +pub trait BucketOrchestrationUpload { + async fn upload_file_with_content_type_process(&self,object_name: &str, + bytes: &[u8], + content_type: &str, + is_public:bool) -> AnyhowResult<()>; +} + + pub struct BucketOrchestration { access_key: String, @@ -11,6 +32,35 @@ pub struct BucketOrchestration { private_bucket_name: String, } +impl BucketOrchestrationDownload for BucketOrchestration { + #[async_trait] + async fn download_file_to_disk( + &self, + object_path: String, + filesystem_path: String, + is_public:bool + ) -> AnyhowResult<()> { + let bucket_client = self.get_bucket_with_visbility(is_public).await?; + bucket_client.download_file_to_disk(object_path, filesystem_path).await + + } +} + +impl BucketOrchestrationUpload for BucketOrchestration { + #[async_trait] + async fn upload_file_with_content_type_process(&self,object_name: &str, + bytes: &[u8], + content_type: &str, + is_public:bool) -> AnyhowResult<()> { + let bucket_client = self.get_bucket_with_visbility(is_public).await?; + bucket_client.upload_file_with_content_type_process( + object_name, + bytes, + content_type + ).await + } +} + impl BucketOrchestration { pub fn new_bucket_client_from_existing_env()-> AnyhowResult { @@ -48,32 +98,9 @@ impl BucketOrchestration { } } - pub async fn download_file_to_disk( - &self, - object_path: String, - filesystem_path: String, - is_public:bool - ) -> AnyhowResult<()> { - let bucket_client = self.get_bucket_with_visbility(is_public).await?; - bucket_client.download_file_to_disk(object_path, filesystem_path).await - - } - - pub async fn upload_file_with_content_type_process(&self,object_name: &str, - bytes: &[u8], - content_type: &str, - is_public:bool) -> AnyhowResult<()> { - let bucket_client = self.get_bucket_with_visbility(is_public).await?; - bucket_client.upload_file_with_content_type_process( - object_name, - bytes, - content_type - ).await - - } async fn get_bucket_with_visbility(&self, public:bool) -> AnyhowResult { - + let bucket_timeout = easyenv::get_env_duration_seconds_or_default( "BUCKET_TIMEOUT_SECONDS", Duration::from_secs(60 * 10)); let bucket_client:BucketClient; diff --git a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_bucket_details.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_bucket_details.rs index 39b9ada6b9..e63d4e2270 100644 --- a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_bucket_details.rs +++ b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_bucket_details.rs @@ -30,8 +30,17 @@ impl RemoteCloudBucketDetails { pub fn file_descriptor_from_bucket_details(&self) -> Box { match self.prefix.as_str() { "loRA" => Box::new(weights_descriptor::WeightsLoRADescriptor {}), - "SD15" => Box::new(weights_descriptor::WeightsSD15Descriptor {}), - "SDXL" => Box::new(weights_descriptor::WeightsSDXLDescriptor {}), + "sd15" => Box::new(weights_descriptor::WeightsSD15Descriptor {}), + "sdxl" => Box::new(weights_descriptor::WeightsSDXLDescriptor {}), + "valle_prompt" => Box::new(weights_descriptor::WeightsVallePromptDescriptor {}), + "rvc" => { + match self.suffix.as_str() { + "safetensors" => Box::new(weights_descriptor::WeightsRVCDescriptor {}), + "index" => Box::new(weights_descriptor::WeightsRVCIndexDescriptor {}), + _ => panic!("Unknown suffix: {}",self.suffix) + } + }, + "svc" => Box::new(weights_descriptor::WeightsSVCDescriptor {}), _ => panic!("Unknown prefix: {}", self.prefix) } } diff --git a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/weights_descriptor.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/weights_descriptor.rs index bccc6aee13..2f6c98d19e 100644 --- a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/weights_descriptor.rs +++ b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/weights_descriptor.rs @@ -73,4 +73,100 @@ impl FileDescriptor for WeightsSDXLDescriptor { fn is_public(&self) -> bool { true } +} + +pub struct WeightsSVCDescriptor {} + +impl FileDescriptor for crate::remote_file_manager::weights_descriptor::WeightsSVCDescriptor { + fn remote_directory_path(&self) -> &str { + return REMOTE_FILE_DIRECTORY; + } + // this will be the type of file peroid is handled by the file formatter + // e.g safetensors bin jpg + fn get_suffix(&self)->String { + return "safetensors".to_string(); + } + // This will be the prefix of the media type or the weights type. + // name of the weights or the name of the media type + // vall-e_prompt, SD15, sd15, sdxl when implmenting add to the end + fn get_prefix(&self)->String { + return "svc".to_string(); + } + + // This will be ensure that the right bucket is picked + fn is_public(&self) -> bool { + true + } +} + +pub struct WeightsRVCDescriptor {} + +impl FileDescriptor for crate::remote_file_manager::weights_descriptor::WeightsRVCDescriptor { + fn remote_directory_path(&self) -> &str { + return REMOTE_FILE_DIRECTORY; + } + // this will be the type of file peroid is handled by the file formatter + // e.g safetensors bin jpg + fn get_suffix(&self)->String { + return "pth".to_string(); + } + // This will be the prefix of the media type or the weights type. + // name of the weights or the name of the media type + // vall-e_prompt, SD15, sd15, sdxl when implmenting add to the end + fn get_prefix(&self)->String { + return "rvc".to_string(); + } + + // This will be ensure that the right bucket is picked + fn is_public(&self) -> bool { + true + } +} + +pub struct WeightsRVCIndexDescriptor {} + +impl FileDescriptor for crate::remote_file_manager::weights_descriptor::WeightsRVCDescriptor { + fn remote_directory_path(&self) -> &str { + return REMOTE_FILE_DIRECTORY; + } + // this will be the type of file peroid is handled by the file formatter + // e.g safetensors bin jpg + fn get_suffix(&self)->String { + return "index".to_string(); + } + // This will be the prefix of the media type or the weights type. + // name of the weights or the name of the media type + // vall-e_prompt, SD15, sd15, sdxl when implmenting add to the end + fn get_prefix(&self)->String { + return "rvc".to_string(); + } + + // This will be ensure that the right bucket is picked + fn is_public(&self) -> bool { + true + } +} + +pub struct WeightsVallePromptDescriptor {} + +impl FileDescriptor for crate::remote_file_manager::weights_descriptor::WeightsVallePromptDescriptor { + fn remote_directory_path(&self) -> &str { + return REMOTE_FILE_DIRECTORY; + } + // this will be the type of file peroid is handled by the file formatter + // e.g safetensors bin jpg + fn get_suffix(&self)->String { + return "safetensors".to_string(); + } + // This will be the prefix of the media type or the weights type. + // name of the weights or the name of the media type + // vall-e_prompt, SD15, sd15, sdxl when implmenting add to the end + fn get_prefix(&self)->String { + return "valle_prompt".to_string(); + } + + // This will be ensure that the right bucket is picked + fn is_public(&self) -> bool { + true + } } \ No newline at end of file diff --git a/crates/lib/api_clients/cloud_storage/src/remote_file_manager_mock/bucket_orchestration_mock.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager_mock/bucket_orchestration_mock.rs new file mode 100644 index 0000000000..d7b13b677a --- /dev/null +++ b/crates/lib/api_clients/cloud_storage/src/remote_file_manager_mock/bucket_orchestration_mock.rs @@ -0,0 +1,5 @@ + + + +struct BucketOrchestrationMock { +} \ No newline at end of file diff --git a/crates/lib/api_clients/cloud_storage/src/remote_file_manager_mock/mod.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager_mock/mod.rs new file mode 100644 index 0000000000..90ad55263e --- /dev/null +++ b/crates/lib/api_clients/cloud_storage/src/remote_file_manager_mock/mod.rs @@ -0,0 +1 @@ +pub mod bucket_orchestration_mock; \ No newline at end of file From 3a5b765e518f1e949d8190d0f4a5f9fc3556e556 Mon Sep 17 00:00:00 2001 From: kasisnu <5044120+kasisnu@users.noreply.github.com> Date: Wed, 6 Dec 2023 22:14:33 +0530 Subject: [PATCH 106/124] send favorite/comment counts with media file list endpoint --- .../queries/media_files/list_media_files.rs | 29 ++++++++++++++++--- .../media_file_social_meta_lite.rs | 21 ++++++++++++++ .../src/http_server/common_responses/mod.rs | 3 +- .../endpoints/media_files/list_media_files.rs | 8 ++++- 4 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 crates/service/web/storyteller_web/src/http_server/common_responses/media_file_social_meta_lite.rs diff --git a/crates/lib/mysql_queries/src/queries/media_files/list_media_files.rs b/crates/lib/mysql_queries/src/queries/media_files/list_media_files.rs index 15571f0563..aab6042dd2 100644 --- a/crates/lib/mysql_queries/src/queries/media_files/list_media_files.rs +++ b/crates/lib/mysql_queries/src/queries/media_files/list_media_files.rs @@ -44,6 +44,9 @@ pub struct MediaFileListItem { pub creator_set_visibility: Visibility, + pub comment_count: u64, + pub favorite_count: u64, + pub created_at: DateTime, pub updated_at: DateTime, } @@ -100,6 +103,8 @@ pub async fn list_media_files(args: ListMediaFilesArgs<'_>) -> AnyhowResult, updated_at: DateTime, } @@ -257,6 +276,8 @@ impl FromRow<'_, MySqlRow> for MediaFileListItemInternal { creator_set_visibility: Visibility::try_from_mysql_row(row, "creator_set_visibility")?, created_at: row.try_get("created_at")?, updated_at: row.try_get("updated_at")?, + comment_count: row.try_get("comment_count")?, + favorite_count: row.try_get("favorite_count")?, }) } } diff --git a/crates/service/web/storyteller_web/src/http_server/common_responses/media_file_social_meta_lite.rs b/crates/service/web/storyteller_web/src/http_server/common_responses/media_file_social_meta_lite.rs new file mode 100644 index 0000000000..04e7e29be8 --- /dev/null +++ b/crates/service/web/storyteller_web/src/http_server/common_responses/media_file_social_meta_lite.rs @@ -0,0 +1,21 @@ +use tokens::tokens::media_files::MediaFileToken; + + +/// Fields useful for enriching media file listings +#[derive(Clone, Serialize)] +pub struct MediaFileSocialMetaLight { + pub favorites_count: u64, + pub comments_count: u64, +} + +impl MediaFileSocialMetaLight { + pub fn from_db_fields( + favorites_count: u64, + comments_count: u64, + ) -> Self { + Self { + favorites_count, + comments_count, + } + } +} diff --git a/crates/service/web/storyteller_web/src/http_server/common_responses/mod.rs b/crates/service/web/storyteller_web/src/http_server/common_responses/mod.rs index d84a319a04..f22f30d692 100644 --- a/crates/service/web/storyteller_web/src/http_server/common_responses/mod.rs +++ b/crates/service/web/storyteller_web/src/http_server/common_responses/mod.rs @@ -1,3 +1,4 @@ pub mod pagination_cursors; pub mod pagination_page; -pub mod user_details_lite; \ No newline at end of file +pub mod user_details_lite; +pub mod media_file_social_meta_lite; \ No newline at end of file diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files.rs index e1c0869e90..05e158c8cc 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files.rs @@ -15,6 +15,7 @@ use enums::by_table::media_files::media_file_type::MediaFileType; use enums::common::visibility::Visibility; use mysql_queries::queries::media_files::list_media_files::{list_media_files, ListMediaFilesArgs, ViewAs}; use tokens::tokens::media_files::MediaFileToken; +use crate::http_server::common_responses::media_file_social_meta_lite::MediaFileSocialMetaLight; use crate::http_server::common_responses::pagination_cursors::PaginationCursors; use crate::http_server::common_responses::user_details_lite::UserDetailsLight; @@ -52,6 +53,7 @@ pub struct MediaFileListItem { pub public_bucket_path: String, pub maybe_creator: Option, + pub maybe_social_meta: Option, pub creator_set_visibility: Visibility, @@ -175,7 +177,7 @@ pub async fn list_media_files_handler( let results = results_page.records.into_iter() .map(|record| MediaFileListItem { - token: record.token, + token: record.token.clone(), origin_category: record.origin_category, origin_product_category: record.origin_product_category, maybe_origin_model_type: record.maybe_origin_model_type, @@ -193,6 +195,10 @@ pub async fn list_media_files_handler( record.maybe_creator_display_name, record.maybe_creator_gravatar_hash, ), + maybe_social_meta: Option::from(MediaFileSocialMetaLight::from_db_fields( + record.favorite_count, + record.comment_count, + )), creator_set_visibility: record.creator_set_visibility, created_at: record.created_at, updated_at: record.updated_at, From 3e8d7be00e4b834c18b9fccd27656ca043951f0a Mon Sep 17 00:00:00 2001 From: kasisnu <5044120+kasisnu@users.noreply.github.com> Date: Mon, 18 Dec 2023 17:53:12 +0530 Subject: [PATCH 107/124] add remaining media files endpoints to openapispec --- .../media_files/media_file_origin_category.rs | 3 +- .../media_file_origin_model_type.rs | 3 +- .../media_file_origin_product_category.rs | 3 +- .../by_table/media_files/media_file_type.rs | 3 +- .../_types/tokens/src/tokens/media_files.rs | 3 +- .../web/storyteller_web/src/api_doc.rs | 36 +++++++---- .../media_file_social_meta_lite.rs | 3 +- .../common_responses/pagination_cursors.rs | 4 +- .../common_responses/pagination_page.rs | 4 +- .../endpoints/media_files/list_media_files.rs | 56 +++++++++++------- .../media_files/list_media_files_for_user.rs | 59 +++++++++++-------- 11 files changed, 113 insertions(+), 64 deletions(-) diff --git a/crates/_types/enums/src/by_table/media_files/media_file_origin_category.rs b/crates/_types/enums/src/by_table/media_files/media_file_origin_category.rs index 39c87a33e0..fd6f36c06e 100644 --- a/crates/_types/enums/src/by_table/media_files/media_file_origin_category.rs +++ b/crates/_types/enums/src/by_table/media_files/media_file_origin_category.rs @@ -6,12 +6,13 @@ use serde::Serialize; use strum::EnumCount; #[cfg(test)] use strum::EnumIter; +use utoipa::ToSchema; /// Used in the `media_files` table in a `VARCHAR` field. /// /// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY. #[cfg_attr(test, derive(EnumIter, EnumCount))] -#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)] +#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize, ToSchema)] #[serde(rename_all = "snake_case")] pub enum MediaFileOriginCategory { /// ML model inference output - uploaded models or zero shot. diff --git a/crates/_types/enums/src/by_table/media_files/media_file_origin_model_type.rs b/crates/_types/enums/src/by_table/media_files/media_file_origin_model_type.rs index fa75c7f791..3fc35a9bb1 100644 --- a/crates/_types/enums/src/by_table/media_files/media_file_origin_model_type.rs +++ b/crates/_types/enums/src/by_table/media_files/media_file_origin_model_type.rs @@ -6,12 +6,13 @@ use serde::Serialize; use strum::EnumCount; #[cfg(test)] use strum::EnumIter; +use utoipa::ToSchema; /// Used in the `media_files` table in a `VARCHAR` field. /// /// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY. #[cfg_attr(test, derive(EnumIter, EnumCount))] -#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)] +#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize, ToSchema)] #[serde(rename_all = "snake_case")] pub enum MediaFileOriginModelType { /// RVC (v2) voice conversion models diff --git a/crates/_types/enums/src/by_table/media_files/media_file_origin_product_category.rs b/crates/_types/enums/src/by_table/media_files/media_file_origin_product_category.rs index e74da29ecf..ccf1266246 100644 --- a/crates/_types/enums/src/by_table/media_files/media_file_origin_product_category.rs +++ b/crates/_types/enums/src/by_table/media_files/media_file_origin_product_category.rs @@ -4,6 +4,7 @@ use std::collections::BTreeSet; use strum::EnumCount; #[cfg(test)] use strum::EnumIter; +use utoipa::ToSchema; /// Used in the `media_files` table in `VARCHAR(16)` field `origin_product_category`. /// @@ -14,7 +15,7 @@ use strum::EnumIter; /// /// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY. #[cfg_attr(test, derive(EnumIter, EnumCount))] -#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)] +#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize, ToSchema)] pub enum MediaFileOriginProductCategory { /// Media files created by (or uploaded for) the Face Animator product. /// The underlying model could be SadTalker, Wav2Lip, or some future model diff --git a/crates/_types/enums/src/by_table/media_files/media_file_type.rs b/crates/_types/enums/src/by_table/media_files/media_file_type.rs index 08fe71f572..8ba5f0ecb9 100644 --- a/crates/_types/enums/src/by_table/media_files/media_file_type.rs +++ b/crates/_types/enums/src/by_table/media_files/media_file_type.rs @@ -4,12 +4,13 @@ use std::collections::BTreeSet; use strum::EnumCount; #[cfg(test)] use strum::EnumIter; +use utoipa::ToSchema; /// Used in the `media_files` table in a `VARCHAR` field. /// /// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY. #[cfg_attr(test, derive(EnumIter, EnumCount))] -#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Deserialize, Serialize)] +#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Deserialize, Serialize, ToSchema)] #[serde(rename_all = "lowercase")] pub enum MediaFileType { /// Audio files: wav, mp3, etc. diff --git a/crates/_types/tokens/src/tokens/media_files.rs b/crates/_types/tokens/src/tokens/media_files.rs index 6fa878d6b1..4a304ca810 100644 --- a/crates/_types/tokens/src/tokens/media_files.rs +++ b/crates/_types/tokens/src/tokens/media_files.rs @@ -2,11 +2,12 @@ use std::fmt::Debug; use serde::Deserialize; use serde::Serialize; +use utoipa::ToSchema; use crate::prefixes::TokenPrefix; /// The primary key for Audit Logs. -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, sqlx::Type, Debug, Serialize, Deserialize)] +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, sqlx::Type, Debug, Serialize, Deserialize, ToSchema)] #[sqlx(transparent)] pub struct MediaFileToken(pub String); diff --git a/crates/service/web/storyteller_web/src/api_doc.rs b/crates/service/web/storyteller_web/src/api_doc.rs index 1d96b220e0..e6808517b7 100644 --- a/crates/service/web/storyteller_web/src/api_doc.rs +++ b/crates/service/web/storyteller_web/src/api_doc.rs @@ -1,4 +1,3 @@ - use crate::http_server::endpoints::voice_designer::inference::enqueue_tts_request::*; use crate::http_server::endpoints::weights::list_available_weights::*; @@ -8,26 +7,36 @@ use crate::http_server::endpoints::weights::get_weight::*; use crate::http_server::endpoints::weights::update_weight::*; use crate::http_server::endpoints::weights::list_weights_by_user::*; use crate::http_server::common_responses::user_details_lite::{DefaultAvatarInfo, UserDetailsLight}; -use enums::by_table::model_weights::{ - weights_types::WeightsType, - weights_category::WeightsCategory, -}; +use crate::http_server::common_responses::media_file_social_meta_lite::MediaFileSocialMetaLight; +use crate::http_server::common_responses::pagination_cursors::PaginationCursors; +use crate::http_server::common_responses::pagination_page::PaginationPage; +use crate::http_server::endpoints::media_files::list_featured_media_files::*; +use crate::http_server::endpoints::media_files::list_media_files::*; +use crate::http_server::endpoints::media_files::list_media_files_for_user::*; +use enums::by_table::model_weights::{weights_types::WeightsType, weights_category::WeightsCategory}; +use enums::by_table::media_files::media_file_type::MediaFileType; +use enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory; +use enums::by_table::media_files::media_file_origin_model_type::MediaFileOriginModelType; +use enums::by_table::media_files::media_file_origin_product_category::MediaFileOriginProductCategory; use tokens::tokens::generic_inference_jobs::*; use tokens::tokens::model_weights::*; use tokens::tokens::users::*; +use tokens::tokens::media_files::*; use enums::common::visibility::Visibility; use chrono::{DateTime, Utc}; use utoipa::OpenApi; - #[derive(OpenApi)] #[openapi(paths(crate::http_server::endpoints::voice_designer::inference::enqueue_tts_request::enqueue_tts_request, crate::http_server::endpoints::weights::list_available_weights::list_available_weights_handler, crate::http_server::endpoints::weights::delete_weight::delete_weight_handler, crate::http_server::endpoints::weights::update_weight::update_weight_handler, crate::http_server::endpoints::weights::get_weight::get_weight_handler, - crate::http_server::endpoints::weights::list_weights_by_user::list_weights_by_user_handler + crate::http_server::endpoints::weights::list_weights_by_user::list_weights_by_user_handler, + crate::http_server::endpoints::media_files::list_featured_media_files::list_featured_media_files_handler, + crate::http_server::endpoints::media_files::list_media_files::list_media_files_handler, + crate::http_server::endpoints::media_files::list_media_files_for_user::list_media_files_for_user_handler ),components(schemas( // Tokens UserToken,Visibility, @@ -40,10 +49,17 @@ use utoipa::OpenApi; GetWeightPathInfo,GetWeightResponse,GetWeightError, UpdateWeightRequest,UpdateWeightRequest,UpdateWeightPathInfo,UpdateWeightRequest,UpdateWeightError, DeleteWeightPathInfo,DeleteWeightRequest,DeleteWeightError,DeleteWeightRequest,DeleteWeightError, - ListWeightError,ModelWeightForList,ListWeightError, + ListWeightError,ModelWeightForList,ListWeightError, ListAvailableWeightsQuery,ListAvailableWeightsSuccessResponse,ModelWeightForList, ListWeightsByUserError,ListWeightsByUserSuccessResponse,ListWeightsByUserPathInfo,Weight, - UserDetailsLight,DefaultAvatarInfo + UserDetailsLight,DefaultAvatarInfo, + PaginationCursors, + PaginationPage, + MediaFileOriginModelType,MediaFileOriginProductCategory,MediaFileOriginCategory, + ListFeaturedMediaFilesSuccessResponse,MediaFile,MediaFileToken,MediaFileType, ListFeaturedMediaFilesError, + ListMediaFilesSuccessResponse, ListMediaFilesError, MediaFileListItem, ListMediaFilesQueryParams, + MediaFileSocialMetaLight, + ListMediaFilesForUserSuccessResponse,ListMediaFilesForUserQueryParams,ListMediaFilesForUserError,ListMediaFilesForUserPathInfo, + MediaFileForUserListItem, MediaFileForUserListItem )))] pub struct ApiDoc; - diff --git a/crates/service/web/storyteller_web/src/http_server/common_responses/media_file_social_meta_lite.rs b/crates/service/web/storyteller_web/src/http_server/common_responses/media_file_social_meta_lite.rs index 04e7e29be8..6f32750d0c 100644 --- a/crates/service/web/storyteller_web/src/http_server/common_responses/media_file_social_meta_lite.rs +++ b/crates/service/web/storyteller_web/src/http_server/common_responses/media_file_social_meta_lite.rs @@ -1,8 +1,9 @@ +use utoipa::ToSchema; use tokens::tokens::media_files::MediaFileToken; /// Fields useful for enriching media file listings -#[derive(Clone, Serialize)] +#[derive(Clone, Serialize, ToSchema)] pub struct MediaFileSocialMetaLight { pub favorites_count: u64, pub comments_count: u64, diff --git a/crates/service/web/storyteller_web/src/http_server/common_responses/pagination_cursors.rs b/crates/service/web/storyteller_web/src/http_server/common_responses/pagination_cursors.rs index c801faea59..be6377ba7e 100644 --- a/crates/service/web/storyteller_web/src/http_server/common_responses/pagination_cursors.rs +++ b/crates/service/web/storyteller_web/src/http_server/common_responses/pagination_cursors.rs @@ -1,10 +1,12 @@ +use utoipa::ToSchema; + /// Pagination by cursors /// These types of pagination are for "infinite scrolling", which do not reveal a number of pages. /// This is good so that investors and competitors cannot reveal how many database records we have. /// This is typically used for "discovery" type pages, not user profiles. /// /// See `PaginationPage` for the other type of pagination. -#[derive(Serialize)] +#[derive(Serialize, ToSchema)] pub struct PaginationCursors { /// The "next" cursor. diff --git a/crates/service/web/storyteller_web/src/http_server/common_responses/pagination_page.rs b/crates/service/web/storyteller_web/src/http_server/common_responses/pagination_page.rs index 50534944ef..83f6d93961 100644 --- a/crates/service/web/storyteller_web/src/http_server/common_responses/pagination_page.rs +++ b/crates/service/web/storyteller_web/src/http_server/common_responses/pagination_page.rs @@ -1,3 +1,5 @@ +use utoipa::ToSchema; + /// Pagination by page id /// This type of pagination is by "page id" and "page count". /// This should never be used to walk the entire public database as competitors and investors @@ -5,7 +7,7 @@ /// This is best used for user profiles and scoped down results. /// /// See `PaginationCursors` for the other type of pagination. -#[derive(Serialize)] +#[derive(Serialize, ToSchema)] pub struct PaginationPage { /// The current page number pub current: usize, diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files.rs index 05e158c8cc..e48d6d00b0 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files.rs @@ -7,6 +7,7 @@ use actix_web::web::{Path, Query}; use chrono::{DateTime, Utc}; use log::{info, warn}; use buckets::public::media_files::bucket_file_path::MediaFileBucketPath; +use utoipa::{IntoParams, path, ToSchema}; use enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory; use enums::by_table::media_files::media_file_origin_model_type::MediaFileOriginModelType; @@ -22,8 +23,8 @@ use crate::http_server::common_responses::user_details_lite::UserDetailsLight; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; use crate::server_state::ServerState; -#[derive(Deserialize)] -pub struct QueryParams { +#[derive(Deserialize, ToSchema, IntoParams)] +pub struct ListMediaFilesQueryParams { pub sort_ascending: Option, pub per_page: Option, pub cursor: Option, @@ -31,14 +32,14 @@ pub struct QueryParams { pub filter_media_type: Option, } -#[derive(Serialize)] -pub struct SuccessResponse { +#[derive(Serialize, ToSchema)] +pub struct ListMediaFilesSuccessResponse { pub success: bool, pub results: Vec, pub pagination: PaginationCursors, } -#[derive(Serialize)] +#[derive(Serialize, ToSchema)] pub struct MediaFileListItem { pub token: MediaFileToken, @@ -61,38 +62,49 @@ pub struct MediaFileListItem { pub updated_at: DateTime, } -#[derive(Debug)] -pub enum ErrorResponse { +#[derive(Debug, ToSchema)] +pub enum ListMediaFilesError { ServerError, } -impl ResponseError for ErrorResponse { +impl ResponseError for ListMediaFilesError { fn status_code(&self) -> StatusCode { match *self { - ErrorResponse::ServerError => StatusCode::INTERNAL_SERVER_ERROR, + ListMediaFilesError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, } } fn error_response(&self) -> HttpResponse { let error_reason = match self { - ErrorResponse::ServerError => "server error".to_string(), + ListMediaFilesError::ServerError => "server error".to_string(), }; to_simple_json_error(&error_reason, self.status_code()) } } -impl std::fmt::Display for ErrorResponse { +impl std::fmt::Display for ListMediaFilesError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{:?}", self) } } +#[utoipa::path( + get, + path = "/v1/media_files/list", + params( + ListMediaFilesQueryParams, + ), + responses( + (status = 200, description = "List Featured Media Files", body = ListMediaFilesSuccessResponse), + (status = 500, description = "Server error", body = ListMediaFilesError), + ), +)] pub async fn list_media_files_handler( - http_request: HttpRequest, - query: Query, - server_state: web::Data> -) -> Result + http_request: HttpRequest, + query: Query, + server_state: web::Data> +) -> Result { let maybe_user_session = server_state .session_checker @@ -100,7 +112,7 @@ pub async fn list_media_files_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - ErrorResponse::ServerError + ListMediaFilesError::ServerError })?; let mut is_mod = false; @@ -122,7 +134,7 @@ pub async fn list_media_files_handler( let cursor = server_state.sort_key_crypto.decrypt_id(cursor) .map_err(|e| { warn!("crypto error: {:?}", e); - ErrorResponse::ServerError + ListMediaFilesError::ServerError })?; Some(cursor as usize) } else { @@ -149,7 +161,7 @@ pub async fn list_media_files_handler( Ok(results) => results, Err(e) => { warn!("Query error: {:?}", e); - return Err(ErrorResponse::ServerError); + return Err(ListMediaFilesError::ServerError); } }; @@ -157,7 +169,7 @@ pub async fn list_media_files_handler( let cursor = server_state.sort_key_crypto.encrypt_id(id as u64) .map_err(|e| { warn!("crypto error: {:?}", e); - ErrorResponse::ServerError + ListMediaFilesError::ServerError })?; Some(cursor) } else { @@ -168,7 +180,7 @@ pub async fn list_media_files_handler( let cursor = server_state.sort_key_crypto.encrypt_id(id as u64) .map_err(|e| { warn!("crypto error: {:?}", e); - ErrorResponse::ServerError + ListMediaFilesError::ServerError })?; Some(cursor) } else { @@ -205,7 +217,7 @@ pub async fn list_media_files_handler( }) .collect::>(); - let response = SuccessResponse { + let response = ListMediaFilesSuccessResponse { success: true, results, pagination: PaginationCursors { @@ -216,7 +228,7 @@ pub async fn list_media_files_handler( }; let body = serde_json::to_string(&response) - .map_err(|e| ErrorResponse::ServerError)?; + .map_err(|e| ListMediaFilesError::ServerError)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files_for_user.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files_for_user.rs index f634072842..788f594ff9 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files_for_user.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files_for_user.rs @@ -7,6 +7,7 @@ use actix_web::web::{Path, Query}; use chrono::{DateTime, Utc}; use log::{info, warn}; use buckets::public::media_files::bucket_file_path::MediaFileBucketPath; +use utoipa::{IntoParams, path, ToSchema}; use enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory; use enums::by_table::media_files::media_file_origin_model_type::MediaFileOriginModelType; @@ -16,18 +17,17 @@ use enums::common::visibility::Visibility; use mysql_queries::queries::media_files::list_media_files_for_user::{list_media_files_for_user, ListMediaFileForUserArgs, ViewAs}; use tokens::tokens::media_files::MediaFileToken; -use crate::http_server::common_responses::pagination_cursors::PaginationCursors; use crate::http_server::common_responses::pagination_page::PaginationPage; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; use crate::server_state::ServerState; -#[derive(Deserialize)] -pub struct PathInfo { +#[derive(Deserialize, ToSchema)] +pub struct ListMediaFilesForUserPathInfo { username: String, } -#[derive(Deserialize)] -pub struct QueryParams { +#[derive(Deserialize, ToSchema, IntoParams)] +pub struct ListMediaFilesForUserQueryParams { pub sort_ascending: Option, pub page_size: Option, pub page_index: Option, @@ -36,15 +36,15 @@ pub struct QueryParams { pub filter_media_type: Option, } -#[derive(Serialize)] -pub struct SuccessResponse { +#[derive(Serialize, ToSchema)] +pub struct ListMediaFilesForUserSuccessResponse { pub success: bool, - pub results: Vec, + pub results: Vec, pub pagination: PaginationPage, } -#[derive(Serialize)] -pub struct MediaFileListItem { +#[derive(Serialize, ToSchema)] +pub struct MediaFileForUserListItem { pub token: MediaFileToken, pub origin_category: MediaFileOriginCategory, @@ -63,39 +63,50 @@ pub struct MediaFileListItem { pub updated_at: DateTime, } -#[derive(Debug)] -pub enum ErrorResponse { +#[derive(Debug, ToSchema)] +pub enum ListMediaFilesForUserError { ServerError, } -impl ResponseError for ErrorResponse { +impl ResponseError for ListMediaFilesForUserError { fn status_code(&self) -> StatusCode { match *self { - ErrorResponse::ServerError => StatusCode::INTERNAL_SERVER_ERROR, + ListMediaFilesForUserError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, } } fn error_response(&self) -> HttpResponse { let error_reason = match self { - ErrorResponse::ServerError => "server error".to_string(), + ListMediaFilesForUserError::ServerError => "server error".to_string(), }; to_simple_json_error(&error_reason, self.status_code()) } } -impl std::fmt::Display for ErrorResponse { +impl std::fmt::Display for ListMediaFilesForUserError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{:?}", self) } } +#[utoipa::path( + get, + path = "/v1/media_files/list/user/{username}", + params( + ListMediaFilesForUserQueryParams, + ), + responses( + (status = 200, description = "List Featured Media Files", body = ListMediaFilesForUserSuccessResponse), + (status = 500, description = "Server error", body = ListMediaFilesForUserError), + ), +)] pub async fn list_media_files_for_user_handler( http_request: HttpRequest, - path: Path, - query: Query, + path: Path, + query: Query, server_state: web::Data> -) -> Result +) -> Result { let maybe_user_session = server_state .session_checker @@ -103,7 +114,7 @@ pub async fn list_media_files_for_user_handler( .await .map_err(|e| { warn!("Session checker error: {:?}", e); - ErrorResponse::ServerError + ListMediaFilesForUserError::ServerError })?; let mut is_author = false; @@ -150,13 +161,13 @@ pub async fn list_media_files_for_user_handler( Ok(results) => results, Err(e) => { warn!("Query error: {:?}", e); - return Err(ErrorResponse::ServerError); + return Err(ListMediaFilesForUserError::ServerError); } }; let results = results_page.records.into_iter() - .map(|record| MediaFileListItem { + .map(|record| MediaFileForUserListItem { token: record.token, origin_category: record.origin_category, origin_product_category: record.origin_product_category, @@ -175,7 +186,7 @@ pub async fn list_media_files_for_user_handler( }) .collect::>(); - let response = SuccessResponse { + let response = ListMediaFilesForUserSuccessResponse { success: true, results, pagination: PaginationPage{ @@ -185,7 +196,7 @@ pub async fn list_media_files_for_user_handler( }; let body = serde_json::to_string(&response) - .map_err(|e| ErrorResponse::ServerError)?; + .map_err(|e| ListMediaFilesForUserError::ServerError)?; Ok(HttpResponse::Ok() .content_type("application/json") From 79d64c51ad51e5d754bb8cd4d9d49054317d0ae0 Mon Sep 17 00:00:00 2001 From: kasisnu <5044120+kasisnu@users.noreply.github.com> Date: Mon, 18 Dec 2023 20:51:58 +0530 Subject: [PATCH 108/124] fix bug with page offsets for public pagination --- .../media_files/list_media_files_for_user.rs | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/crates/lib/mysql_queries/src/queries/media_files/list_media_files_for_user.rs b/crates/lib/mysql_queries/src/queries/media_files/list_media_files_for_user.rs index c8f32280d8..0cb86a90ba 100644 --- a/crates/lib/mysql_queries/src/queries/media_files/list_media_files_for_user.rs +++ b/crates/lib/mysql_queries/src/queries/media_files/list_media_files_for_user.rs @@ -73,9 +73,6 @@ pub async fn list_media_files_for_user(args: ListMediaFileForUserArgs<'_>) -> An let row_count_query = count_query_builder.build_query_scalar::(); let row_count_result = row_count_query.fetch_one(args.mysql_pool).await?; - /// Figure out limit start and end based on page size and indexes as requested - let limit_start = args.page_size * args.page_index; - let limit_end = limit_start + args.page_size; /// Now fetch the actual results with all the fields let result_fields = select_result_fields(); @@ -83,8 +80,8 @@ pub async fn list_media_files_for_user(args: ListMediaFileForUserArgs<'_>) -> An args.maybe_filter_media_type, args.username, true, - limit_start, - limit_end, + args.page_index, + args.page_size, args.cursor_is_reversed, args.view_as, result_fields.as_str(), @@ -157,8 +154,8 @@ fn query_builder<'a>( maybe_filter_media_type: Option, username: &'a str, enforce_limits: bool, - limit_start: usize, - limit_end: usize, + page_index: usize, + page_size: usize, cursor_is_reversed: bool, view_as: ViewAs, select_fields: &'a str, @@ -208,11 +205,8 @@ WHERE m.user_deleted_at IS NULL } if enforce_limits { - if cursor_is_reversed { - query_builder.push(format!(" LIMIT {limit_start}, {limit_end} ")); - } else { - query_builder.push(format!(" LIMIT {limit_end}, {limit_start} ")); - } + let offset = page_index * page_size; + query_builder.push(format!(" LIMIT {page_size} OFFSET {offset} ")); } query_builder From c52d197717e53e69721aedd37110ad4906f0c9ba Mon Sep 17 00:00:00 2001 From: Kasisnu <5044120+kasisnu@users.noreply.github.com> Date: Tue, 19 Dec 2023 15:51:17 +0530 Subject: [PATCH 109/124] sort user media file results by creation date --- .../media_files/list_media_files_for_user.rs | 16 ++++++++-------- .../media_files/list_media_files_for_user.rs | 5 +---- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/crates/lib/mysql_queries/src/queries/media_files/list_media_files_for_user.rs b/crates/lib/mysql_queries/src/queries/media_files/list_media_files_for_user.rs index 0cb86a90ba..cfe474efbf 100644 --- a/crates/lib/mysql_queries/src/queries/media_files/list_media_files_for_user.rs +++ b/crates/lib/mysql_queries/src/queries/media_files/list_media_files_for_user.rs @@ -51,7 +51,7 @@ pub struct ListMediaFileForUserArgs<'a> { pub maybe_filter_media_type: Option, pub page_size: usize, pub page_index: usize, - pub cursor_is_reversed: bool, + pub sort_ascending: bool, pub view_as: ViewAs, pub mysql_pool: &'a MySqlPool, } @@ -66,7 +66,7 @@ pub async fn list_media_files_for_user(args: ListMediaFileForUserArgs<'_>) -> An false, 0, 0, - args.cursor_is_reversed, + args.sort_ascending, args.view_as, count_fields.as_str(), ); @@ -82,7 +82,7 @@ pub async fn list_media_files_for_user(args: ListMediaFileForUserArgs<'_>) -> An true, args.page_index, args.page_size, - args.cursor_is_reversed, + args.sort_ascending, args.view_as, result_fields.as_str(), ); @@ -112,7 +112,7 @@ pub async fn list_media_files_for_user(args: ListMediaFileForUserArgs<'_>) -> An Ok(MediaFileListPage { records: results, - sort_ascending: !args.cursor_is_reversed, + sort_ascending: args.sort_ascending, current_page: args.page_index, total_page_count: number_of_pages, }) @@ -156,7 +156,7 @@ fn query_builder<'a>( enforce_limits: bool, page_index: usize, page_size: usize, - cursor_is_reversed: bool, + sort_ascending: bool, view_as: ViewAs, select_fields: &'a str, ) -> QueryBuilder<'a, MySql> { @@ -198,10 +198,10 @@ WHERE m.user_deleted_at IS NULL } } - if cursor_is_reversed { - query_builder.push(" ORDER BY m.id ASC "); + if sort_ascending { + query_builder.push(" ORDER BY m.created_at ASC "); } else { - query_builder.push(" ORDER BY m.id DESC "); + query_builder.push(" ORDER BY m.created_at DESC "); } if enforce_limits { diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files_for_user.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files_for_user.rs index 788f594ff9..f066cea8c8 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files_for_user.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files_for_user.rs @@ -31,8 +31,6 @@ pub struct ListMediaFilesForUserQueryParams { pub sort_ascending: Option, pub page_size: Option, pub page_index: Option, - pub cursor: Option, - pub cursor_is_reversed: Option, pub filter_media_type: Option, } @@ -132,7 +130,6 @@ pub async fn list_media_files_for_user_handler( let limit = query.page_size.unwrap_or(25); let sort_ascending = query.sort_ascending.unwrap_or(false); - let cursor_is_reversed = query.cursor_is_reversed.unwrap_or(false); let page_size = query.page_size.unwrap_or_else(|| 25); let page_index = query.page_index.unwrap_or_else(|| 0); @@ -151,7 +148,7 @@ pub async fn list_media_files_for_user_handler( maybe_filter_media_type: query.filter_media_type, page_size, page_index, - cursor_is_reversed, + sort_ascending, view_as, mysql_pool: &server_state.mysql_pool, }).await; From ed97cdbb0d218ef8f5cffba8dfa10efe8f46268d Mon Sep 17 00:00:00 2001 From: Michael Chung Date: Thu, 21 Dec 2023 02:25:20 -0500 Subject: [PATCH 110/124] Ok builds again going to run unit tests. --- Cargo.lock | 7 +++-- .../lib/api_clients/cloud_storage/Cargo.toml | 4 +-- .../bucket_orchestration.rs | 27 ++++++++++--------- .../remote_cloud_file_manager.rs | 3 +++ .../remote_file_manager/weights_descriptor.rs | 2 +- 5 files changed, 25 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1e791d92eb..682adb88aa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -620,9 +620,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.74" +version = "0.1.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9" +checksum = "fdf6721fb0140e4f897002dd086c06f6c27775df19cfe1fccb21181a48fd2c98" dependencies = [ "proc-macro2", "quote", @@ -1124,9 +1124,11 @@ name = "cloud_storage" version = "0.0.1" dependencies = [ "anyhow", + "async-trait", "buckets", "crockford", "easyenv", + "env_logger", "errors", "filesys", "hashing", @@ -1134,6 +1136,7 @@ dependencies = [ "mimetypes", "my-workspace-hack", "rust-s3", + "storyteller_root", "tokio", ] diff --git a/crates/lib/api_clients/cloud_storage/Cargo.toml b/crates/lib/api_clients/cloud_storage/Cargo.toml index 86a3de927e..1d874aa09c 100644 --- a/crates/lib/api_clients/cloud_storage/Cargo.toml +++ b/crates/lib/api_clients/cloud_storage/Cargo.toml @@ -30,8 +30,7 @@ my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" } anyhow = "1.0.75" log = "0.4.14" env_logger = "0.10.1" -async-trait = "0.1.58" - +async-trait = "0.1.75" # The "never-encode-slash" feature seems to have been removed: # https://github.com/durch/rust-s3/pull/254 rust-s3 = { version = "0.33.0" } @@ -39,3 +38,4 @@ rust-s3 = { version = "0.33.0" } # Runtime # NB: We switched to Tokio from `async-std` for broader ecosystem support. tokio = { version = "1.34.0", features = ["macros"] } + diff --git a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/bucket_orchestration.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/bucket_orchestration.rs index 4d071769f0..3641348d65 100644 --- a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/bucket_orchestration.rs +++ b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/bucket_orchestration.rs @@ -1,9 +1,11 @@ -use errors::AnyhowResult; -use crate::bucket_client::BucketClient; -use tokio::time::Duration; use log::info; -use crate::remote_file_manager_mock::bucket_orchestration_mock; +use tokio::time::Duration; + use async_trait::async_trait; +use errors::AnyhowResult; + +use crate::bucket_client::BucketClient; + #[async_trait] pub trait BucketOrchestrationDownload { async fn download_file_to_disk( @@ -16,14 +18,12 @@ pub trait BucketOrchestrationDownload { #[async_trait] pub trait BucketOrchestrationUpload { - async fn upload_file_with_content_type_process(&self,object_name: &str, + async fn upload_file_with_content_type_process(&self,object_name: &str, bytes: &[u8], content_type: &str, is_public:bool) -> AnyhowResult<()>; } - - pub struct BucketOrchestration { access_key: String, secret_key: String, @@ -32,9 +32,10 @@ pub struct BucketOrchestration { private_bucket_name: String, } +#[async_trait] impl BucketOrchestrationDownload for BucketOrchestration { - #[async_trait] - async fn download_file_to_disk( + + async fn download_file_to_disk( &self, object_path: String, filesystem_path: String, @@ -42,13 +43,13 @@ impl BucketOrchestrationDownload for BucketOrchestration { ) -> AnyhowResult<()> { let bucket_client = self.get_bucket_with_visbility(is_public).await?; bucket_client.download_file_to_disk(object_path, filesystem_path).await - } } -impl BucketOrchestrationUpload for BucketOrchestration { - #[async_trait] - async fn upload_file_with_content_type_process(&self,object_name: &str, +#[async_trait] + impl BucketOrchestrationUpload for BucketOrchestration { + + async fn upload_file_with_content_type_process(&self,object_name: &str, bytes: &[u8], content_type: &str, is_public:bool) -> AnyhowResult<()> { diff --git a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_file_manager.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_file_manager.rs index fa0bfee894..dd472cbd78 100644 --- a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_file_manager.rs +++ b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_file_manager.rs @@ -25,6 +25,8 @@ use storyteller_root::get_seed_tool_data_root; use std::path::Path; use bucket_orchestration::BucketOrchestration; +use crate::remote_file_manager::bucket_orchestration::{BucketOrchestrationDownload, BucketOrchestrationUpload}; + struct RemoteCloudFileClient { bucket_orchestration_client: BucketOrchestration } @@ -42,6 +44,7 @@ impl RemoteCloudFileClient { let full_remote_cloud_file_path = file_bucket_directory.get_full_remote_cloud_file_path().to_string(); let is_public = file_descriptor.is_public().clone(); + self.bucket_orchestration_client.download_file_to_disk(full_remote_cloud_file_path, to_system_file_path, is_public).await?; Ok(()) } diff --git a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/weights_descriptor.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/weights_descriptor.rs index 2f6c98d19e..e988d84e2f 100644 --- a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/weights_descriptor.rs +++ b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/weights_descriptor.rs @@ -125,7 +125,7 @@ impl FileDescriptor for crate::remote_file_manager::weights_descriptor::WeightsR pub struct WeightsRVCIndexDescriptor {} -impl FileDescriptor for crate::remote_file_manager::weights_descriptor::WeightsRVCDescriptor { +impl FileDescriptor for crate::remote_file_manager::weights_descriptor::WeightsRVCIndexDescriptor { fn remote_directory_path(&self) -> &str { return REMOTE_FILE_DIRECTORY; } From 11c17f0a1dd4b25ae0bd7961a1b05ac1df403943 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Thu, 21 Dec 2023 02:37:29 -0500 Subject: [PATCH 111/124] fix lints --- .../src/job/job_loop/determine_dependency_status.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/service/job/inference_job/src/job/job_loop/determine_dependency_status.rs b/crates/service/job/inference_job/src/job/job_loop/determine_dependency_status.rs index 5af55d57fa..9a79c77746 100644 --- a/crates/service/job/inference_job/src/job/job_loop/determine_dependency_status.rs +++ b/crates/service/job/inference_job/src/job/job_loop/determine_dependency_status.rs @@ -9,7 +9,6 @@ use filesys::file_exists::file_exists; use migration::voice_conversion::query_vc_model_for_migration::{query_vc_model_for_migration, VcModel, VcModelError, VcModelType}; use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob; use mysql_queries::queries::tts::tts_models::get_tts_model_for_inference_improved::{get_tts_model_for_inference_improved, TtsModelForInferenceError, TtsModelForInferenceRecord}; -use mysql_queries::queries::voice_conversion::inference::get_voice_conversion_model_for_inference::VoiceConversionModelForInferenceError; use crate::job::job_loop::process_single_job_error::ProcessSingleJobError; use crate::job_dependencies::JobDependencies; From 5e48a6193a085fc6a9318fcc07cad47ddbb6651c Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Thu, 21 Dec 2023 02:57:00 -0500 Subject: [PATCH 112/124] reorganize modules --- .../src/seeding/seed_media_files.rs | 2 +- crates/cli/dev-upload-media-file/src/main.rs | 2 +- .../insert_media_file_from_cli_tool.rs | 0 .../insert_media_file_from_face_animation.rs | 0 .../insert_media_file_from_file_upload.rs | 0 .../insert_media_file_from_rerender.rs | 0 .../insert_media_file_from_tacotron2.rs | 0 .../insert_media_file_from_voice_conversion.rs | 0 .../insert_media_file_from_zero_shot_tts.rs | 0 .../src/queries/media_files/create/mod.rs | 7 +++++++ .../media_files/{ => list}/list_media_files.rs | 0 .../{ => list}/list_media_files_by_tokens.rs | 0 .../{ => list}/list_media_files_for_user.rs | 0 .../src/queries/media_files/list/mod.rs | 3 +++ .../mysql_queries/src/queries/media_files/mod.rs | 12 ++---------- .../job_types/lipsync/sad_talker/process_job.rs | 2 +- .../tacotron2_v2_early_fakeyou/upload_results.rs | 2 +- .../tts/vall_e_x/process_job_inference_voice.rs | 4 ++-- .../src/job/job_types/vc/rvc_v2/process_job.rs | 2 +- .../job/job_types/vc/so_vits_svc/process_job.rs | 2 +- .../videofilter/rerender_a_video/process_job.rs | 2 +- .../media_files/list_featured_media_files.rs | 15 +++------------ .../endpoints/media_files/list_media_files.rs | 12 ++++++------ .../media_files/list_media_files_for_user.rs | 8 ++++---- .../upload/process_upload_media_file.rs | 2 +- .../endpoints/weights/list_weights_by_user.rs | 6 +++--- 26 files changed, 38 insertions(+), 45 deletions(-) rename crates/lib/mysql_queries/src/queries/media_files/{ => create}/insert_media_file_from_cli_tool.rs (100%) rename crates/lib/mysql_queries/src/queries/media_files/{ => create}/insert_media_file_from_face_animation.rs (100%) rename crates/lib/mysql_queries/src/queries/media_files/{ => create}/insert_media_file_from_file_upload.rs (100%) rename crates/lib/mysql_queries/src/queries/media_files/{ => create}/insert_media_file_from_rerender.rs (100%) rename crates/lib/mysql_queries/src/queries/media_files/{ => create}/insert_media_file_from_tacotron2.rs (100%) rename crates/lib/mysql_queries/src/queries/media_files/{ => create}/insert_media_file_from_voice_conversion.rs (100%) rename crates/lib/mysql_queries/src/queries/media_files/{ => create}/insert_media_file_from_zero_shot_tts.rs (100%) create mode 100644 crates/lib/mysql_queries/src/queries/media_files/create/mod.rs rename crates/lib/mysql_queries/src/queries/media_files/{ => list}/list_media_files.rs (100%) rename crates/lib/mysql_queries/src/queries/media_files/{ => list}/list_media_files_by_tokens.rs (100%) rename crates/lib/mysql_queries/src/queries/media_files/{ => list}/list_media_files_for_user.rs (100%) create mode 100644 crates/lib/mysql_queries/src/queries/media_files/list/mod.rs diff --git a/crates/cli/dev-database-seed/src/seeding/seed_media_files.rs b/crates/cli/dev-database-seed/src/seeding/seed_media_files.rs index 1e3f2c3c80..1132ef9bad 100644 --- a/crates/cli/dev-database-seed/src/seeding/seed_media_files.rs +++ b/crates/cli/dev-database-seed/src/seeding/seed_media_files.rs @@ -13,8 +13,8 @@ use filesys::path_to_string::path_to_string; use hashing::sha256::sha256_hash_file::sha256_hash_file; use mimetypes::mimetype_for_bytes::get_mimetype_for_bytes; use mimetypes::mimetype_for_file::get_mimetype_for_file; +use mysql_queries::queries::media_files::create::insert_media_file_from_cli_tool::{insert_media_file_from_cli_tool, InsertArgs}; use mysql_queries::queries::media_files::get_media_file::get_media_file; -use mysql_queries::queries::media_files::insert_media_file_from_cli_tool::{insert_media_file_from_cli_tool, InsertArgs}; use storyteller_root::get_seed_tool_data_root; use tokens::tokens::media_files::MediaFileToken; use tokens::tokens::users::UserToken; diff --git a/crates/cli/dev-upload-media-file/src/main.rs b/crates/cli/dev-upload-media-file/src/main.rs index 3928071c5d..87bcd5665e 100644 --- a/crates/cli/dev-upload-media-file/src/main.rs +++ b/crates/cli/dev-upload-media-file/src/main.rs @@ -11,7 +11,7 @@ use enums::common::visibility::Visibility; use errors::{AnyhowResult, bail}; use filesys::file_read_bytes::file_read_bytes; use mimetypes::mimetype_for_bytes::get_mimetype_for_bytes; -use mysql_queries::queries::media_files::insert_media_file_from_cli_tool::{insert_media_file_from_cli_tool, InsertArgs}; +use mysql_queries::queries::media_files::create::insert_media_file_from_cli_tool::{insert_media_file_from_cli_tool, InsertArgs}; use crate::cli_args::parse_cli_args; diff --git a/crates/lib/mysql_queries/src/queries/media_files/insert_media_file_from_cli_tool.rs b/crates/lib/mysql_queries/src/queries/media_files/create/insert_media_file_from_cli_tool.rs similarity index 100% rename from crates/lib/mysql_queries/src/queries/media_files/insert_media_file_from_cli_tool.rs rename to crates/lib/mysql_queries/src/queries/media_files/create/insert_media_file_from_cli_tool.rs diff --git a/crates/lib/mysql_queries/src/queries/media_files/insert_media_file_from_face_animation.rs b/crates/lib/mysql_queries/src/queries/media_files/create/insert_media_file_from_face_animation.rs similarity index 100% rename from crates/lib/mysql_queries/src/queries/media_files/insert_media_file_from_face_animation.rs rename to crates/lib/mysql_queries/src/queries/media_files/create/insert_media_file_from_face_animation.rs diff --git a/crates/lib/mysql_queries/src/queries/media_files/insert_media_file_from_file_upload.rs b/crates/lib/mysql_queries/src/queries/media_files/create/insert_media_file_from_file_upload.rs similarity index 100% rename from crates/lib/mysql_queries/src/queries/media_files/insert_media_file_from_file_upload.rs rename to crates/lib/mysql_queries/src/queries/media_files/create/insert_media_file_from_file_upload.rs diff --git a/crates/lib/mysql_queries/src/queries/media_files/insert_media_file_from_rerender.rs b/crates/lib/mysql_queries/src/queries/media_files/create/insert_media_file_from_rerender.rs similarity index 100% rename from crates/lib/mysql_queries/src/queries/media_files/insert_media_file_from_rerender.rs rename to crates/lib/mysql_queries/src/queries/media_files/create/insert_media_file_from_rerender.rs diff --git a/crates/lib/mysql_queries/src/queries/media_files/insert_media_file_from_tacotron2.rs b/crates/lib/mysql_queries/src/queries/media_files/create/insert_media_file_from_tacotron2.rs similarity index 100% rename from crates/lib/mysql_queries/src/queries/media_files/insert_media_file_from_tacotron2.rs rename to crates/lib/mysql_queries/src/queries/media_files/create/insert_media_file_from_tacotron2.rs diff --git a/crates/lib/mysql_queries/src/queries/media_files/insert_media_file_from_voice_conversion.rs b/crates/lib/mysql_queries/src/queries/media_files/create/insert_media_file_from_voice_conversion.rs similarity index 100% rename from crates/lib/mysql_queries/src/queries/media_files/insert_media_file_from_voice_conversion.rs rename to crates/lib/mysql_queries/src/queries/media_files/create/insert_media_file_from_voice_conversion.rs diff --git a/crates/lib/mysql_queries/src/queries/media_files/insert_media_file_from_zero_shot_tts.rs b/crates/lib/mysql_queries/src/queries/media_files/create/insert_media_file_from_zero_shot_tts.rs similarity index 100% rename from crates/lib/mysql_queries/src/queries/media_files/insert_media_file_from_zero_shot_tts.rs rename to crates/lib/mysql_queries/src/queries/media_files/create/insert_media_file_from_zero_shot_tts.rs diff --git a/crates/lib/mysql_queries/src/queries/media_files/create/mod.rs b/crates/lib/mysql_queries/src/queries/media_files/create/mod.rs new file mode 100644 index 0000000000..b01e5bb277 --- /dev/null +++ b/crates/lib/mysql_queries/src/queries/media_files/create/mod.rs @@ -0,0 +1,7 @@ +pub mod insert_media_file_from_cli_tool; +pub mod insert_media_file_from_face_animation; +pub mod insert_media_file_from_file_upload; +pub mod insert_media_file_from_rerender; +pub mod insert_media_file_from_tacotron2; +pub mod insert_media_file_from_voice_conversion; +pub mod insert_media_file_from_zero_shot_tts; diff --git a/crates/lib/mysql_queries/src/queries/media_files/list_media_files.rs b/crates/lib/mysql_queries/src/queries/media_files/list/list_media_files.rs similarity index 100% rename from crates/lib/mysql_queries/src/queries/media_files/list_media_files.rs rename to crates/lib/mysql_queries/src/queries/media_files/list/list_media_files.rs diff --git a/crates/lib/mysql_queries/src/queries/media_files/list_media_files_by_tokens.rs b/crates/lib/mysql_queries/src/queries/media_files/list/list_media_files_by_tokens.rs similarity index 100% rename from crates/lib/mysql_queries/src/queries/media_files/list_media_files_by_tokens.rs rename to crates/lib/mysql_queries/src/queries/media_files/list/list_media_files_by_tokens.rs diff --git a/crates/lib/mysql_queries/src/queries/media_files/list_media_files_for_user.rs b/crates/lib/mysql_queries/src/queries/media_files/list/list_media_files_for_user.rs similarity index 100% rename from crates/lib/mysql_queries/src/queries/media_files/list_media_files_for_user.rs rename to crates/lib/mysql_queries/src/queries/media_files/list/list_media_files_for_user.rs diff --git a/crates/lib/mysql_queries/src/queries/media_files/list/mod.rs b/crates/lib/mysql_queries/src/queries/media_files/list/mod.rs new file mode 100644 index 0000000000..41103a9363 --- /dev/null +++ b/crates/lib/mysql_queries/src/queries/media_files/list/mod.rs @@ -0,0 +1,3 @@ +pub mod list_media_files; +pub mod list_media_files_by_tokens; +pub mod list_media_files_for_user; diff --git a/crates/lib/mysql_queries/src/queries/media_files/mod.rs b/crates/lib/mysql_queries/src/queries/media_files/mod.rs index cfdc3eb3c8..0215d99857 100644 --- a/crates/lib/mysql_queries/src/queries/media_files/mod.rs +++ b/crates/lib/mysql_queries/src/queries/media_files/mod.rs @@ -1,13 +1,5 @@ +pub mod create; pub mod delete_media_file; pub mod get_media_file; -pub mod insert_media_file_from_cli_tool; -pub mod insert_media_file_from_face_animation; -pub mod insert_media_file_from_file_upload; -pub mod insert_media_file_from_rerender; -pub mod insert_media_file_from_tacotron2; -pub mod insert_media_file_from_voice_conversion; -pub mod insert_media_file_from_zero_shot_tts; -pub mod list_media_files; -pub mod list_media_files_by_tokens; -pub mod list_media_files_for_user; +pub mod list; pub mod update_media_file; diff --git a/crates/service/job/inference_job/src/job/job_types/lipsync/sad_talker/process_job.rs b/crates/service/job/inference_job/src/job/job_types/lipsync/sad_talker/process_job.rs index 57852d2b4b..fdeb1ba53e 100644 --- a/crates/service/job/inference_job/src/job/job_types/lipsync/sad_talker/process_job.rs +++ b/crates/service/job/inference_job/src/job/job_types/lipsync/sad_talker/process_job.rs @@ -13,7 +13,7 @@ use filesys::safe_delete_temp_file::safe_delete_temp_file; use hashing::sha256::sha256_hash_file::sha256_hash_file; use mimetypes::mimetype_for_file::get_mimetype_for_file; use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob; -use mysql_queries::queries::media_files::insert_media_file_from_face_animation::{insert_media_file_from_face_animation, InsertArgs}; +use mysql_queries::queries::media_files::create::insert_media_file_from_face_animation::{insert_media_file_from_face_animation, InsertArgs}; use tokens::tokens::users::UserToken; use crate::job::job_loop::job_success_result::{JobSuccessResult, ResultEntity}; diff --git a/crates/service/job/inference_job/src/job/job_types/tts/tacotron2_v2_early_fakeyou/upload_results.rs b/crates/service/job/inference_job/src/job/job_types/tts/tacotron2_v2_early_fakeyou/upload_results.rs index e2a7547f42..756c478ff9 100644 --- a/crates/service/job/inference_job/src/job/job_types/tts/tacotron2_v2_early_fakeyou/upload_results.rs +++ b/crates/service/job/inference_job/src/job/job_types/tts/tacotron2_v2_early_fakeyou/upload_results.rs @@ -13,7 +13,7 @@ use hashing::sha256::sha256_hash_string::sha256_hash_string; use jobs_common::job_progress_reporter::job_progress_reporter::JobProgressReporter; use mysql_queries::column_types::vocoder_type::VocoderType; use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob; -use mysql_queries::queries::media_files::insert_media_file_from_tacotron2::{insert_media_file_from_tacotron2, InsertMediaFileArgs}; +use mysql_queries::queries::media_files::create::insert_media_file_from_tacotron2::{insert_media_file_from_tacotron2, InsertMediaFileArgs}; use mysql_queries::queries::tts::tts_results::insert_tts_result::insert_tts_result; use mysql_queries::queries::tts::tts_results::insert_tts_result::JobType; diff --git a/crates/service/job/inference_job/src/job/job_types/tts/vall_e_x/process_job_inference_voice.rs b/crates/service/job/inference_job/src/job/job_types/tts/vall_e_x/process_job_inference_voice.rs index 76f4940796..72272f4fab 100644 --- a/crates/service/job/inference_job/src/job/job_types/tts/vall_e_x/process_job_inference_voice.rs +++ b/crates/service/job/inference_job/src/job/job_types/tts/vall_e_x/process_job_inference_voice.rs @@ -13,8 +13,8 @@ use cloud_storage::bucket_path_unifier::BucketPathUnifier; use enums::by_table::generic_inference_jobs::inference_result_type::InferenceResultType; use filesys::file_size::file_size; use hashing::sha256::sha256_hash_file::sha256_hash_file; -use mysql_queries::queries::media_files::insert_media_file_from_zero_shot_tts::insert_media_file_from_zero_shot; -use mysql_queries::queries::media_files::insert_media_file_from_zero_shot_tts::InsertArgs; +use mysql_queries::queries::media_files::create::insert_media_file_from_zero_shot_tts::insert_media_file_from_zero_shot; +use mysql_queries::queries::media_files::create::insert_media_file_from_zero_shot_tts::InsertArgs; use mysql_queries::queries::voice_designer::voices::get_voice::{get_voice_by_token, ZsVoice}; use crate::job::job_loop::job_success_result::JobSuccessResult; diff --git a/crates/service/job/inference_job/src/job/job_types/vc/rvc_v2/process_job.rs b/crates/service/job/inference_job/src/job/job_types/vc/rvc_v2/process_job.rs index 6d2d6c906d..0d2f22e34b 100644 --- a/crates/service/job/inference_job/src/job/job_types/vc/rvc_v2/process_job.rs +++ b/crates/service/job/inference_job/src/job/job_types/vc/rvc_v2/process_job.rs @@ -19,7 +19,7 @@ use migration::voice_conversion::query_vc_model_for_migration::VcModel; use mimetypes::mimetype_for_file::get_mimetype_for_file; use mysql_queries::payloads::generic_inference_args::generic_inference_args::PolymorphicInferenceArgs; use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob; -use mysql_queries::queries::media_files::insert_media_file_from_voice_conversion::{insert_media_file_from_voice_conversion, InsertMediaFileArgs, VoiceConversionModelType}; +use mysql_queries::queries::media_files::create::insert_media_file_from_voice_conversion::{insert_media_file_from_voice_conversion, InsertMediaFileArgs, VoiceConversionModelType}; use mysql_queries::queries::media_uploads::get_media_upload_for_inference::MediaUploadRecordForInference; use tokens::tokens::media_uploads::MediaUploadToken; use tokens::tokens::model_weights::ModelWeightToken; diff --git a/crates/service/job/inference_job/src/job/job_types/vc/so_vits_svc/process_job.rs b/crates/service/job/inference_job/src/job/job_types/vc/so_vits_svc/process_job.rs index e8c0078479..a46e8c89f5 100644 --- a/crates/service/job/inference_job/src/job/job_types/vc/so_vits_svc/process_job.rs +++ b/crates/service/job/inference_job/src/job/job_types/vc/so_vits_svc/process_job.rs @@ -18,7 +18,7 @@ use migration::voice_conversion::query_vc_model_for_migration::VcModel; use mimetypes::mimetype_for_file::get_mimetype_for_file; use mysql_queries::payloads::generic_inference_args::generic_inference_args::PolymorphicInferenceArgs; use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob; -use mysql_queries::queries::media_files::insert_media_file_from_voice_conversion::{insert_media_file_from_voice_conversion, InsertMediaFileArgs, VoiceConversionModelType}; +use mysql_queries::queries::media_files::create::insert_media_file_from_voice_conversion::{insert_media_file_from_voice_conversion, InsertMediaFileArgs, VoiceConversionModelType}; use mysql_queries::queries::media_uploads::get_media_upload_for_inference::MediaUploadRecordForInference; use tokens::tokens::media_uploads::MediaUploadToken; use tokens::tokens::model_weights::ModelWeightToken; diff --git a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/process_job.rs b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/process_job.rs index cce8a0b8b5..ed47b9ba7f 100644 --- a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/process_job.rs +++ b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/process_job.rs @@ -15,7 +15,7 @@ use hashing::sha256::sha256_hash_file::sha256_hash_file; use mimetypes::mimetype_for_file::get_mimetype_for_file; use mysql_queries::payloads::generic_inference_args::generic_inference_args::PolymorphicInferenceArgs::Rr; use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob; -use mysql_queries::queries::media_files::insert_media_file_from_rerender::{insert_media_file_from_rerender, InsertArgs}; +use mysql_queries::queries::media_files::create::insert_media_file_from_rerender::{insert_media_file_from_rerender, InsertArgs}; use mysql_queries::queries::model_weights::get_weight::get_weight_by_token; use crate::job::job_loop::job_success_result::{JobSuccessResult, ResultEntity}; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_featured_media_files.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_featured_media_files.rs index 55cbfaef7b..240d27b3c5 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_featured_media_files.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_featured_media_files.rs @@ -7,20 +7,11 @@ use chrono::{DateTime, Utc}; use log::{debug, error, warn}; use r2d2_redis::redis::Commands; use utoipa::ToSchema; -use buckets::public::media_files::bucket_file_path::MediaFileBucketPath; -use enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory; -use enums::by_table::media_files::media_file_origin_model_type::MediaFileOriginModelType; -use enums::by_table::media_files::media_file_origin_product_category::MediaFileOriginProductCategory; -use enums::by_table::media_files::media_file_type::MediaFileType; -use enums::by_table::model_weights::{ - weights_category::WeightsCategory, - weights_types::WeightsType, -}; -use mysql_queries::queries::media_files::list_media_files_by_tokens::list_media_files_by_tokens; -use mysql_queries::queries::model_weights::list_weights_by_tokens::list_weights_by_tokens; +use buckets::public::media_files::bucket_file_path::MediaFileBucketPath; +use enums::by_table::media_files::media_file_type::MediaFileType; +use mysql_queries::queries::media_files::list::list_media_files_by_tokens::list_media_files_by_tokens; use tokens::tokens::media_files::MediaFileToken; -use tokens::tokens::model_weights::ModelWeightToken; use crate::http_server::common_responses::user_details_lite::UserDetailsLight; use crate::server_state::ServerState; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files.rs index e48d6d00b0..af61ace678 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files.rs @@ -3,21 +3,21 @@ use std::sync::Arc; use actix_web::{HttpMessage, HttpRequest, HttpResponse, web}; use actix_web::error::ResponseError; use actix_web::http::StatusCode; -use actix_web::web::{Path, Query}; +use actix_web::web::Query; use chrono::{DateTime, Utc}; -use log::{info, warn}; -use buckets::public::media_files::bucket_file_path::MediaFileBucketPath; -use utoipa::{IntoParams, path, ToSchema}; +use log::warn; +use utoipa::{IntoParams, ToSchema}; +use buckets::public::media_files::bucket_file_path::MediaFileBucketPath; use enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory; use enums::by_table::media_files::media_file_origin_model_type::MediaFileOriginModelType; use enums::by_table::media_files::media_file_origin_product_category::MediaFileOriginProductCategory; use enums::by_table::media_files::media_file_type::MediaFileType; use enums::common::visibility::Visibility; -use mysql_queries::queries::media_files::list_media_files::{list_media_files, ListMediaFilesArgs, ViewAs}; +use mysql_queries::queries::media_files::list::list_media_files::{list_media_files, ListMediaFilesArgs, ViewAs}; use tokens::tokens::media_files::MediaFileToken; -use crate::http_server::common_responses::media_file_social_meta_lite::MediaFileSocialMetaLight; +use crate::http_server::common_responses::media_file_social_meta_lite::MediaFileSocialMetaLight; use crate::http_server::common_responses::pagination_cursors::PaginationCursors; use crate::http_server::common_responses::user_details_lite::UserDetailsLight; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files_for_user.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files_for_user.rs index f066cea8c8..2792561418 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files_for_user.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files_for_user.rs @@ -5,16 +5,16 @@ use actix_web::error::ResponseError; use actix_web::http::StatusCode; use actix_web::web::{Path, Query}; use chrono::{DateTime, Utc}; -use log::{info, warn}; -use buckets::public::media_files::bucket_file_path::MediaFileBucketPath; -use utoipa::{IntoParams, path, ToSchema}; +use log::warn; +use utoipa::{IntoParams, ToSchema}; +use buckets::public::media_files::bucket_file_path::MediaFileBucketPath; use enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory; use enums::by_table::media_files::media_file_origin_model_type::MediaFileOriginModelType; use enums::by_table::media_files::media_file_origin_product_category::MediaFileOriginProductCategory; use enums::by_table::media_files::media_file_type::MediaFileType; use enums::common::visibility::Visibility; -use mysql_queries::queries::media_files::list_media_files_for_user::{list_media_files_for_user, ListMediaFileForUserArgs, ViewAs}; +use mysql_queries::queries::media_files::list::list_media_files_for_user::{list_media_files_for_user, ListMediaFileForUserArgs, ViewAs}; use tokens::tokens::media_files::MediaFileToken; use crate::http_server::common_responses::pagination_page::PaginationPage; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload/process_upload_media_file.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload/process_upload_media_file.rs index df23ab1240..8956b54e5b 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload/process_upload_media_file.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/upload/process_upload_media_file.rs @@ -12,7 +12,7 @@ use hashing::sha256::sha256_hash_bytes::sha256_hash_bytes; use http_server_common::request::get_request_ip::get_request_ip; use media::decode_basic_audio_info::decode_basic_audio_bytes_info; use mimetypes::mimetype_for_bytes::get_mimetype_for_bytes; -use mysql_queries::queries::media_files::insert_media_file_from_file_upload::{insert_media_file_from_file_upload, InsertMediaFileFromUploadArgs, UploadType}; +use mysql_queries::queries::media_files::create::insert_media_file_from_file_upload::{insert_media_file_from_file_upload, InsertMediaFileFromUploadArgs, UploadType}; use tokens::tokens::media_files::MediaFileToken; use crate::http_server::endpoints::media_files::upload::drain_multipart_request::{drain_multipart_request, MediaFileUploadSource}; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/list_weights_by_user.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/list_weights_by_user.rs index 364a14fdde..54df007a1b 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/list_weights_by_user.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/list_weights_by_user.rs @@ -7,14 +7,14 @@ use actix_web::http::StatusCode; use actix_web::web::Path; use chrono::{DateTime, Utc}; use log::warn; +use utoipa::ToSchema; use enums::common::visibility::Visibility; -use mysql_queries::queries::model_weights::list_weights_by_user::{list_weights_by_creator_username, WeightsJoinUserRecord}; +use mysql_queries::queries::model_weights::list_weights_by_user::list_weights_by_creator_username; use tokens::tokens::model_weights::ModelWeightToken; use crate::http_server::common_responses::user_details_lite::UserDetailsLight; use crate::server_state::ServerState; -use utoipa::ToSchema; #[derive(Serialize, Clone,ToSchema)] pub struct Weight { @@ -159,7 +159,7 @@ pub async fn list_weights_by_user_handler( let final_weights:Vec; // if it's not the user ... then only show public weights else show private and public - if (creator_user_token != user_session.user_token) { + if creator_user_token != user_session.user_token { final_weights = weights.into_iter().filter(|weight| { weight.creator_set_visibility == Visibility::Public }).collect(); From 64806135c5c7aeb5726e586729c29692cd60274a Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Thu, 21 Dec 2023 03:56:07 -0500 Subject: [PATCH 113/124] model weight avatars --- ...788b757af2dc895b229385101f3b96cd9b51.json} | 55 ++++-- ...58f99f63edacbab6bf4a0c43732884c8f11a.json} | 55 ++++-- ...2a47faf01e5d16d1030e15a7e2da161dd0d80.json | 12 ++ .../src/queries/model_weights/edit/mod.rs | 1 + .../edit/set_model_weight_avatar.rs | 32 ++++ .../src/queries/model_weights/get_weight.rs | 27 +++ .../src/queries/model_weights/mod.rs | 1 + .../rerender_a_video/process_job.rs | 2 +- .../endpoints/weights/get_weight.rs | 19 +- .../src/http_server/endpoints/weights/mod.rs | 1 + .../weights/set_model_weight_avatar.rs | 172 ++++++++++++++++++ .../service/web/storyteller_web/src/routes.rs | 14 +- 12 files changed, 360 insertions(+), 31 deletions(-) rename .sqlx/{query-7434b13f252c43b854e51c7761a71842076694c31cfc9336863638f829388727.json => query-a63aa483bc3a8906a5fa61362534788b757af2dc895b229385101f3b96cd9b51.json} (83%) rename .sqlx/{query-964cda4c4505907fd8af46b2f6578a62ab5bba7cc5534469c3c061f9cfb0cd50.json => query-a9ee4dedd7375b2baec864892d1358f99f63edacbab6bf4a0c43732884c8f11a.json} (82%) create mode 100644 .sqlx/query-bda002b24b98328f0fb0440cfc82a47faf01e5d16d1030e15a7e2da161dd0d80.json create mode 100644 crates/lib/mysql_queries/src/queries/model_weights/edit/mod.rs create mode 100644 crates/lib/mysql_queries/src/queries/model_weights/edit/set_model_weight_avatar.rs create mode 100644 crates/service/web/storyteller_web/src/http_server/endpoints/weights/set_model_weight_avatar.rs diff --git a/.sqlx/query-7434b13f252c43b854e51c7761a71842076694c31cfc9336863638f829388727.json b/.sqlx/query-a63aa483bc3a8906a5fa61362534788b757af2dc895b229385101f3b96cd9b51.json similarity index 83% rename from .sqlx/query-7434b13f252c43b854e51c7761a71842076694c31cfc9336863638f829388727.json rename to .sqlx/query-a63aa483bc3a8906a5fa61362534788b757af2dc895b229385101f3b96cd9b51.json index 45f8663bbd..b9439a6d6f 100644 --- a/.sqlx/query-7434b13f252c43b854e51c7761a71842076694c31cfc9336863638f829388727.json +++ b/.sqlx/query-a63aa483bc3a8906a5fa61362534788b757af2dc895b229385101f3b96cd9b51.json @@ -1,6 +1,6 @@ { "db_name": "MySQL", - "query": "\n SELECT\n wt.token as `token: tokens::tokens::model_weights::ModelWeightToken`,\n wt.title,\n wt.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n wt.weights_category as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n wt.maybe_thumbnail_token,\n wt.description_markdown,\n wt.description_rendered_html,\n wt.creator_user_token as `creator_user_token: tokens::tokens::users::UserToken`,\n wt.creator_ip_address,\n wt.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n wt.maybe_last_update_user_token as `maybe_last_update_user_token: tokens::tokens::users::UserToken`,\n wt.original_download_url,\n wt.original_filename,\n wt.file_size_bytes,\n wt.file_checksum_sha2,\n wt.public_bucket_hash,\n wt.maybe_public_bucket_prefix,\n wt.maybe_public_bucket_extension,\n wt.cached_user_ratings_negative_count,\n wt.cached_user_ratings_positive_count,\n wt.cached_user_ratings_total_count,\n wt.maybe_cached_user_ratings_ratio,\n wt.cached_user_ratings_last_updated_at,\n wt.version,\n wt.created_at,\n wt.updated_at,\n wt.user_deleted_at,\n wt.mod_deleted_at\n FROM model_weights as wt\n WHERE\n wt.token = ?\n AND wt.user_deleted_at IS NULL\n AND wt.mod_deleted_at IS NULL\n ", + "query": "\n SELECT\n wt.token as `token: tokens::tokens::model_weights::ModelWeightToken`,\n wt.title,\n wt.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n wt.weights_category as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n wt.maybe_thumbnail_token,\n wt.description_markdown,\n wt.description_rendered_html,\n wt.creator_user_token as `creator_user_token: tokens::tokens::users::UserToken`,\n wt.creator_ip_address,\n wt.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n wt.maybe_last_update_user_token as `maybe_last_update_user_token: tokens::tokens::users::UserToken`,\n wt.original_download_url,\n wt.original_filename,\n wt.file_size_bytes,\n wt.file_checksum_sha2,\n wt.public_bucket_hash,\n wt.maybe_public_bucket_prefix,\n wt.maybe_public_bucket_extension,\n\n avatar.public_bucket_directory_hash as maybe_avatar_public_bucket_hash,\n avatar.maybe_public_bucket_prefix as maybe_avatar_public_bucket_prefix,\n avatar.maybe_public_bucket_extension as maybe_avatar_public_bucket_extension,\n\n wt.cached_user_ratings_negative_count,\n wt.cached_user_ratings_positive_count,\n wt.cached_user_ratings_total_count,\n wt.maybe_cached_user_ratings_ratio,\n wt.cached_user_ratings_last_updated_at,\n wt.version,\n wt.created_at,\n wt.updated_at,\n wt.user_deleted_at,\n wt.mod_deleted_at\n FROM model_weights as wt\n LEFT OUTER JOIN media_files as avatar\n ON avatar.token = wt.maybe_avatar_media_file_token\n WHERE\n wt.token = ?\n ", "describe": { "columns": [ { @@ -185,6 +185,36 @@ }, { "ordinal": 18, + "name": "maybe_avatar_public_bucket_hash", + "type_info": { + "type": "VarString", + "flags": "BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 128 + } + }, + { + "ordinal": 19, + "name": "maybe_avatar_public_bucket_prefix", + "type_info": { + "type": "VarString", + "flags": "BINARY", + "char_set": 224, + "max_size": 64 + } + }, + { + "ordinal": 20, + "name": "maybe_avatar_public_bucket_extension", + "type_info": { + "type": "VarString", + "flags": "BINARY", + "char_set": 224, + "max_size": 64 + } + }, + { + "ordinal": 21, "name": "cached_user_ratings_negative_count", "type_info": { "type": "Long", @@ -194,7 +224,7 @@ } }, { - "ordinal": 19, + "ordinal": 22, "name": "cached_user_ratings_positive_count", "type_info": { "type": "Long", @@ -204,7 +234,7 @@ } }, { - "ordinal": 20, + "ordinal": 23, "name": "cached_user_ratings_total_count", "type_info": { "type": "Long", @@ -214,7 +244,7 @@ } }, { - "ordinal": 21, + "ordinal": 24, "name": "maybe_cached_user_ratings_ratio", "type_info": { "type": "Float", @@ -224,7 +254,7 @@ } }, { - "ordinal": 22, + "ordinal": 25, "name": "cached_user_ratings_last_updated_at", "type_info": { "type": "Timestamp", @@ -234,7 +264,7 @@ } }, { - "ordinal": 23, + "ordinal": 26, "name": "version", "type_info": { "type": "Long", @@ -244,7 +274,7 @@ } }, { - "ordinal": 24, + "ordinal": 27, "name": "created_at", "type_info": { "type": "Timestamp", @@ -254,7 +284,7 @@ } }, { - "ordinal": 25, + "ordinal": 28, "name": "updated_at", "type_info": { "type": "Timestamp", @@ -264,7 +294,7 @@ } }, { - "ordinal": 26, + "ordinal": 29, "name": "user_deleted_at", "type_info": { "type": "Timestamp", @@ -274,7 +304,7 @@ } }, { - "ordinal": 27, + "ordinal": 30, "name": "mod_deleted_at", "type_info": { "type": "Timestamp", @@ -306,6 +336,9 @@ false, true, true, + true, + true, + true, false, false, false, @@ -318,5 +351,5 @@ true ] }, - "hash": "7434b13f252c43b854e51c7761a71842076694c31cfc9336863638f829388727" + "hash": "a63aa483bc3a8906a5fa61362534788b757af2dc895b229385101f3b96cd9b51" } diff --git a/.sqlx/query-964cda4c4505907fd8af46b2f6578a62ab5bba7cc5534469c3c061f9cfb0cd50.json b/.sqlx/query-a9ee4dedd7375b2baec864892d1358f99f63edacbab6bf4a0c43732884c8f11a.json similarity index 82% rename from .sqlx/query-964cda4c4505907fd8af46b2f6578a62ab5bba7cc5534469c3c061f9cfb0cd50.json rename to .sqlx/query-a9ee4dedd7375b2baec864892d1358f99f63edacbab6bf4a0c43732884c8f11a.json index dc4967438c..af12d367e2 100644 --- a/.sqlx/query-964cda4c4505907fd8af46b2f6578a62ab5bba7cc5534469c3c061f9cfb0cd50.json +++ b/.sqlx/query-a9ee4dedd7375b2baec864892d1358f99f63edacbab6bf4a0c43732884c8f11a.json @@ -1,6 +1,6 @@ { "db_name": "MySQL", - "query": "\n SELECT\n wt.token as `token: tokens::tokens::model_weights::ModelWeightToken`,\n wt.title,\n wt.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n wt.weights_category as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n wt.maybe_thumbnail_token,\n wt.description_markdown,\n wt.description_rendered_html,\n wt.creator_user_token as `creator_user_token: tokens::tokens::users::UserToken`,\n wt.creator_ip_address,\n wt.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n wt.maybe_last_update_user_token as `maybe_last_update_user_token: tokens::tokens::users::UserToken`,\n wt.original_download_url,\n wt.original_filename,\n wt.file_size_bytes,\n wt.file_checksum_sha2,\n wt.public_bucket_hash,\n wt.maybe_public_bucket_prefix,\n wt.maybe_public_bucket_extension,\n wt.cached_user_ratings_negative_count,\n wt.cached_user_ratings_positive_count,\n wt.cached_user_ratings_total_count,\n wt.maybe_cached_user_ratings_ratio,\n wt.cached_user_ratings_last_updated_at,\n wt.version,\n wt.created_at,\n wt.updated_at,\n wt.user_deleted_at,\n wt.mod_deleted_at\n FROM model_weights as wt\n WHERE\n wt.token = ?\n ", + "query": "\n SELECT\n wt.token as `token: tokens::tokens::model_weights::ModelWeightToken`,\n wt.title,\n wt.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n wt.weights_category as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n wt.maybe_thumbnail_token,\n wt.description_markdown,\n wt.description_rendered_html,\n wt.creator_user_token as `creator_user_token: tokens::tokens::users::UserToken`,\n wt.creator_ip_address,\n wt.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n wt.maybe_last_update_user_token as `maybe_last_update_user_token: tokens::tokens::users::UserToken`,\n wt.original_download_url,\n wt.original_filename,\n wt.file_size_bytes,\n wt.file_checksum_sha2,\n wt.public_bucket_hash,\n wt.maybe_public_bucket_prefix,\n wt.maybe_public_bucket_extension,\n\n avatar.public_bucket_directory_hash as maybe_avatar_public_bucket_hash,\n avatar.maybe_public_bucket_prefix as maybe_avatar_public_bucket_prefix,\n avatar.maybe_public_bucket_extension as maybe_avatar_public_bucket_extension,\n\n wt.cached_user_ratings_negative_count,\n wt.cached_user_ratings_positive_count,\n wt.cached_user_ratings_total_count,\n wt.maybe_cached_user_ratings_ratio,\n wt.cached_user_ratings_last_updated_at,\n wt.version,\n wt.created_at,\n wt.updated_at,\n wt.user_deleted_at,\n wt.mod_deleted_at\n FROM model_weights as wt\n LEFT OUTER JOIN media_files as avatar\n ON avatar.token = wt.maybe_avatar_media_file_token\n WHERE\n wt.token = ?\n AND wt.user_deleted_at IS NULL\n AND wt.mod_deleted_at IS NULL\n ", "describe": { "columns": [ { @@ -185,6 +185,36 @@ }, { "ordinal": 18, + "name": "maybe_avatar_public_bucket_hash", + "type_info": { + "type": "VarString", + "flags": "BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 128 + } + }, + { + "ordinal": 19, + "name": "maybe_avatar_public_bucket_prefix", + "type_info": { + "type": "VarString", + "flags": "BINARY", + "char_set": 224, + "max_size": 64 + } + }, + { + "ordinal": 20, + "name": "maybe_avatar_public_bucket_extension", + "type_info": { + "type": "VarString", + "flags": "BINARY", + "char_set": 224, + "max_size": 64 + } + }, + { + "ordinal": 21, "name": "cached_user_ratings_negative_count", "type_info": { "type": "Long", @@ -194,7 +224,7 @@ } }, { - "ordinal": 19, + "ordinal": 22, "name": "cached_user_ratings_positive_count", "type_info": { "type": "Long", @@ -204,7 +234,7 @@ } }, { - "ordinal": 20, + "ordinal": 23, "name": "cached_user_ratings_total_count", "type_info": { "type": "Long", @@ -214,7 +244,7 @@ } }, { - "ordinal": 21, + "ordinal": 24, "name": "maybe_cached_user_ratings_ratio", "type_info": { "type": "Float", @@ -224,7 +254,7 @@ } }, { - "ordinal": 22, + "ordinal": 25, "name": "cached_user_ratings_last_updated_at", "type_info": { "type": "Timestamp", @@ -234,7 +264,7 @@ } }, { - "ordinal": 23, + "ordinal": 26, "name": "version", "type_info": { "type": "Long", @@ -244,7 +274,7 @@ } }, { - "ordinal": 24, + "ordinal": 27, "name": "created_at", "type_info": { "type": "Timestamp", @@ -254,7 +284,7 @@ } }, { - "ordinal": 25, + "ordinal": 28, "name": "updated_at", "type_info": { "type": "Timestamp", @@ -264,7 +294,7 @@ } }, { - "ordinal": 26, + "ordinal": 29, "name": "user_deleted_at", "type_info": { "type": "Timestamp", @@ -274,7 +304,7 @@ } }, { - "ordinal": 27, + "ordinal": 30, "name": "mod_deleted_at", "type_info": { "type": "Timestamp", @@ -306,6 +336,9 @@ false, true, true, + true, + true, + true, false, false, false, @@ -318,5 +351,5 @@ true ] }, - "hash": "964cda4c4505907fd8af46b2f6578a62ab5bba7cc5534469c3c061f9cfb0cd50" + "hash": "a9ee4dedd7375b2baec864892d1358f99f63edacbab6bf4a0c43732884c8f11a" } diff --git a/.sqlx/query-bda002b24b98328f0fb0440cfc82a47faf01e5d16d1030e15a7e2da161dd0d80.json b/.sqlx/query-bda002b24b98328f0fb0440cfc82a47faf01e5d16d1030e15a7e2da161dd0d80.json new file mode 100644 index 0000000000..d465e7e1ab --- /dev/null +++ b/.sqlx/query-bda002b24b98328f0fb0440cfc82a47faf01e5d16d1030e15a7e2da161dd0d80.json @@ -0,0 +1,12 @@ +{ + "db_name": "MySQL", + "query": "\n UPDATE model_weights\n SET\n maybe_avatar_media_file_token = ?\n WHERE token = ?\n LIMIT 1\n ", + "describe": { + "columns": [], + "parameters": { + "Right": 2 + }, + "nullable": [] + }, + "hash": "bda002b24b98328f0fb0440cfc82a47faf01e5d16d1030e15a7e2da161dd0d80" +} diff --git a/crates/lib/mysql_queries/src/queries/model_weights/edit/mod.rs b/crates/lib/mysql_queries/src/queries/model_weights/edit/mod.rs new file mode 100644 index 0000000000..d2628b7b1e --- /dev/null +++ b/crates/lib/mysql_queries/src/queries/model_weights/edit/mod.rs @@ -0,0 +1 @@ +pub mod set_model_weight_avatar; \ No newline at end of file diff --git a/crates/lib/mysql_queries/src/queries/model_weights/edit/set_model_weight_avatar.rs b/crates/lib/mysql_queries/src/queries/model_weights/edit/set_model_weight_avatar.rs new file mode 100644 index 0000000000..436f2e766e --- /dev/null +++ b/crates/lib/mysql_queries/src/queries/model_weights/edit/set_model_weight_avatar.rs @@ -0,0 +1,32 @@ +use sqlx::MySqlPool; + +use errors::AnyhowResult; +use tokens::tokens::media_files::MediaFileToken; +use tokens::tokens::model_weights::ModelWeightToken; + +pub struct UpdateArgs<'a> { + pub model_weight_token: &'a ModelWeightToken, + pub maybe_avatar_media_file_token: Option<&'a MediaFileToken>, + //pub update_ip_address: &'a str, + pub mysql_pool: &'a MySqlPool +} + +pub async fn set_model_weight_avatar(args: UpdateArgs<'_>) -> AnyhowResult<()>{ + let transaction = args.mysql_pool.begin().await?; + + let query_result = sqlx::query!( + r#" + UPDATE model_weights + SET + maybe_avatar_media_file_token = ? + WHERE token = ? + LIMIT 1 + "#, + args.maybe_avatar_media_file_token, + args.model_weight_token, + ).execute(args.mysql_pool).await; + + transaction.commit().await?; + + Ok(()) +} diff --git a/crates/lib/mysql_queries/src/queries/model_weights/get_weight.rs b/crates/lib/mysql_queries/src/queries/model_weights/get_weight.rs index d97a660eb0..7dba007d6c 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/get_weight.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/get_weight.rs @@ -33,6 +33,11 @@ pub struct RetrivedModelWeight { pub public_bucket_hash: String, pub maybe_public_bucket_prefix: Option, pub maybe_public_bucket_extension: Option, + + pub maybe_avatar_public_bucket_hash: Option, + pub maybe_avatar_public_bucket_prefix: Option, + pub maybe_avatar_public_bucket_extension: Option, + pub cached_user_ratings_negative_count: u32, pub cached_user_ratings_positive_count: u32, pub cached_user_ratings_total_count: u32, @@ -98,6 +103,9 @@ pub async fn get_weights_by_token_with_connection( public_bucket_hash: record.public_bucket_hash, maybe_public_bucket_prefix: record.maybe_public_bucket_prefix, maybe_public_bucket_extension: record.maybe_public_bucket_extension, + maybe_avatar_public_bucket_hash: record.maybe_avatar_public_bucket_hash, + maybe_avatar_public_bucket_prefix: record.maybe_avatar_public_bucket_prefix, + maybe_avatar_public_bucket_extension: record.maybe_avatar_public_bucket_extension, cached_user_ratings_negative_count: record.cached_user_ratings_negative_count, cached_user_ratings_positive_count: record.cached_user_ratings_positive_count, cached_user_ratings_total_count: record.cached_user_ratings_total_count, @@ -139,6 +147,11 @@ async fn select_include_deleted( wt.public_bucket_hash, wt.maybe_public_bucket_prefix, wt.maybe_public_bucket_extension, + + avatar.public_bucket_directory_hash as maybe_avatar_public_bucket_hash, + avatar.maybe_public_bucket_prefix as maybe_avatar_public_bucket_prefix, + avatar.maybe_public_bucket_extension as maybe_avatar_public_bucket_extension, + wt.cached_user_ratings_negative_count, wt.cached_user_ratings_positive_count, wt.cached_user_ratings_total_count, @@ -150,6 +163,8 @@ async fn select_include_deleted( wt.user_deleted_at, wt.mod_deleted_at FROM model_weights as wt + LEFT OUTER JOIN media_files as avatar + ON avatar.token = wt.maybe_avatar_media_file_token WHERE wt.token = ? "#, @@ -187,6 +202,11 @@ async fn select_without_deleted( wt.public_bucket_hash, wt.maybe_public_bucket_prefix, wt.maybe_public_bucket_extension, + + avatar.public_bucket_directory_hash as maybe_avatar_public_bucket_hash, + avatar.maybe_public_bucket_prefix as maybe_avatar_public_bucket_prefix, + avatar.maybe_public_bucket_extension as maybe_avatar_public_bucket_extension, + wt.cached_user_ratings_negative_count, wt.cached_user_ratings_positive_count, wt.cached_user_ratings_total_count, @@ -198,6 +218,8 @@ async fn select_without_deleted( wt.user_deleted_at, wt.mod_deleted_at FROM model_weights as wt + LEFT OUTER JOIN media_files as avatar + ON avatar.token = wt.maybe_avatar_media_file_token WHERE wt.token = ? AND wt.user_deleted_at IS NULL @@ -229,6 +251,11 @@ pub struct RawWeight { pub public_bucket_hash: String, pub maybe_public_bucket_prefix: Option, pub maybe_public_bucket_extension: Option, + + pub maybe_avatar_public_bucket_hash: Option, + pub maybe_avatar_public_bucket_prefix: Option, + pub maybe_avatar_public_bucket_extension: Option, + pub cached_user_ratings_negative_count: u32, pub cached_user_ratings_positive_count: u32, pub cached_user_ratings_total_count: u32, diff --git a/crates/lib/mysql_queries/src/queries/model_weights/mod.rs b/crates/lib/mysql_queries/src/queries/model_weights/mod.rs index c42a3f6d9d..3be8bbd553 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/mod.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/mod.rs @@ -1,6 +1,7 @@ pub mod create; pub mod create_weight; pub mod delete_weights; +pub mod edit; pub mod get_weight; pub mod inference; pub mod list; diff --git a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/process_job.rs b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/process_job.rs index ed47b9ba7f..7de58ac925 100644 --- a/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/process_job.rs +++ b/crates/service/job/inference_job/src/job/job_types/videofilter/rerender_a_video/process_job.rs @@ -4,8 +4,8 @@ use std::time::Instant; use anyhow::{anyhow, Error}; use log::{error, info, warn}; use serde::{Deserialize, Serialize}; -use buckets::public::media_files::bucket_file_path::MediaFileBucketPath; +use buckets::public::media_files::bucket_file_path::MediaFileBucketPath; use enums::by_table::generic_inference_jobs::inference_result_type::InferenceResultType; use filesys::check_file_exists::check_file_exists; use filesys::file_size::file_size; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/get_weight.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/get_weight.rs index 0b3f059aae..bafc95499e 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/get_weight.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/get_weight.rs @@ -19,6 +19,7 @@ use enums::by_table::model_weights::weights_types::WeightsType; use enums::by_table::model_weights::weights_category::WeightsCategory; use utoipa::ToSchema; +use buckets::public::media_files::bucket_file_path::MediaFileBucketPath; #[derive(Serialize, Clone, ToSchema)] pub struct GetWeightResponse { @@ -34,7 +35,10 @@ pub struct GetWeightResponse { file_size_bytes: i32, file_checksum_sha2: String, - + + /// If an avatar is set, this is the path to the asset. + maybe_avatar_public_bucket_path: Option, + cached_user_ratings_negative_count: u32, cached_user_ratings_positive_count: u32, cached_user_ratings_total_count: u32, @@ -137,8 +141,18 @@ pub async fn get_weight_handler( if is_private && creator_user_token.as_str() != &user_session.user_token { warn!("user is not allowed to view this weight: {}", user_session.user_token); return Err(GetWeightError::NotAuthorized); - } + } + let maybe_avatar = weight.maybe_avatar_public_bucket_hash + .as_deref() + .map(|hash| { + MediaFileBucketPath::from_object_hash( + hash, + weight.maybe_public_bucket_prefix.as_deref(), + weight.maybe_public_bucket_extension.as_deref()) + .get_full_object_path_str() + .to_string() + }); let response = GetWeightResponse { success: true, @@ -149,6 +163,7 @@ pub async fn get_weight_handler( maybe_thumbnail_token: weight.maybe_thumbnail_token, description_markdown: weight.description_markdown, description_rendered_html: weight.description_rendered_html, + maybe_avatar_public_bucket_path: maybe_avatar, creator_set_visibility: weight.creator_set_visibility, file_size_bytes: weight.file_size_bytes, file_checksum_sha2: weight.file_checksum_sha2, diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/mod.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/mod.rs index f52604fe31..f97eaca121 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/mod.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/mod.rs @@ -3,6 +3,7 @@ pub mod get_weight; pub mod list_available_weights; pub mod list_featured_weights; pub mod list_weights_by_user; +pub mod set_model_weight_avatar; pub mod update_weight; // pub mod create_weight; this is a private api call internally // pub mod drain_multipart_weights_request; \ No newline at end of file diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/set_model_weight_avatar.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/set_model_weight_avatar.rs new file mode 100644 index 0000000000..effe9f289f --- /dev/null +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/set_model_weight_avatar.rs @@ -0,0 +1,172 @@ +use std::fmt; +use std::sync::Arc; + +use actix_web::{HttpRequest, HttpResponse, web}; +use actix_web::error::ResponseError; +use actix_web::http::StatusCode; +use actix_web::web::Path; +use log::warn; + +use enums::by_table::media_files::media_file_type::MediaFileType; +use enums::common::visibility::Visibility; +use http_server_common::request::get_request_ip::get_request_ip; +use http_server_common::response::response_success_helpers::simple_json_success; +use http_server_common::response::serialize_as_json_error::serialize_as_json_error; +use mysql_queries::queries::media_files::get_media_file::get_media_file; +use mysql_queries::queries::model_weights::edit::set_model_weight_avatar::{set_model_weight_avatar, UpdateArgs}; +use mysql_queries::queries::model_weights::get_weight::get_weight_by_token; +use tokens::tokens::media_files::MediaFileToken; +use tokens::tokens::model_weights::ModelWeightToken; + +use crate::server_state::ServerState; + +#[derive(Deserialize)] +pub struct SetModelWeightAvatarRequest { + pub avatar_media_file_token: Option, +} + +#[derive(Serialize)] +pub struct SetModelWeightAvatarResponse { + pub success: bool, +} + +/// For the URL PathInfo +#[derive(Deserialize)] +pub struct SetModelWeightAvatarPathInfo { + token: ModelWeightToken, +} + +// =============== Error Response =============== + +#[derive(Debug, Serialize)] +pub enum SetModelWeightAvatarError { + BadInput(String), + NotFound, + NotAuthorized, + ServerError, +} + +impl ResponseError for SetModelWeightAvatarError { + fn status_code(&self) -> StatusCode { + match *self { + SetModelWeightAvatarError::BadInput(_) => StatusCode::BAD_REQUEST, + SetModelWeightAvatarError::NotFound => StatusCode::NOT_FOUND, + SetModelWeightAvatarError::NotAuthorized => StatusCode::UNAUTHORIZED, + SetModelWeightAvatarError::ServerError => StatusCode::INTERNAL_SERVER_ERROR, + } + } + + fn error_response(&self) -> HttpResponse { + serialize_as_json_error(self) + } +} + +// NB: Not using derive_more::Display since Clion doesn't understand it. +impl fmt::Display for SetModelWeightAvatarError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", self) + } +} + +// =============== Handler =============== + +pub async fn set_model_weight_avatar_handler( + http_request: HttpRequest, + path: Path, + request: web::Json, + server_state: web::Data>) -> Result +{ + let maybe_user_session = server_state + .session_checker + .maybe_get_user_session(&http_request, &server_state.mysql_pool) + .await + .map_err(|e| { + warn!("Session checker error: {:?}", e); + SetModelWeightAvatarError::ServerError + })?; + + let user_session = match maybe_user_session { + Some(session) => session, + None => { + warn!("not logged in"); + return Err(SetModelWeightAvatarError::NotAuthorized); + } + }; + + let media_file_token = path.token.clone(); + + let is_mod = user_session.can_ban_users; + + let model_weight_lookup_result = get_weight_by_token( + &path.token, + is_mod, + &server_state.mysql_pool, + ).await; + + let model_weight = match model_weight_lookup_result { + Ok(Some(model_weight)) => model_weight, + Ok(None) => { + warn!("Model weight not found: {:?}", &path.token); + return Err(SetModelWeightAvatarError::NotFound); + }, + Err(err) => { + warn!("Error looking up model_weights : {:?}", err); + return Err(SetModelWeightAvatarError::ServerError); + } + }; + + let is_creator = model_weight.creator_user_token.as_str() == &user_session.user_token; + + if !is_creator && !is_mod { + warn!("user is not allowed to edit this media_file: {}", user_session.user_token); + return Err(SetModelWeightAvatarError::NotAuthorized); + } + + let mut maybe_set_media_file_token = None; + + if let Some(media_file_token) = &request.avatar_media_file_token { + let media_file_lookup_result = get_media_file( + &media_file_token, + false, + &server_state.mysql_pool, + ).await; + + let media_file = match media_file_lookup_result { + Ok(Some(model_weight)) => model_weight, + Ok(None) => { + warn!("Media file not found: {:?}", media_file_token); + return Err(SetModelWeightAvatarError::NotFound); + }, + Err(err) => { + warn!("Error looking up model_weights : {:?}", err); + return Err(SetModelWeightAvatarError::ServerError); + } + }; + + if media_file.creator_set_visibility != Visibility::Public + || media_file.media_type != MediaFileType::Image { + return Err(SetModelWeightAvatarError::BadInput("Invalid media file token.".to_string())); + } + + maybe_set_media_file_token = Some(media_file.token); + } + + // TODO(bt,2023-12-21): DB needs a column, or we need an ip audit log + let _ip_address = get_request_ip(&http_request); + + let query_result = set_model_weight_avatar(UpdateArgs { + model_weight_token: &path.token, + maybe_avatar_media_file_token: maybe_set_media_file_token.as_ref(), + mysql_pool: &server_state.mysql_pool + }).await; + + match query_result { + Ok(_) => {}, + Err(err) => { + warn!("Update MediaFile DB error: {:?}", err); + return Err(SetModelWeightAvatarError::ServerError); + } + }; + + Ok(simple_json_success()) +} diff --git a/crates/service/web/storyteller_web/src/routes.rs b/crates/service/web/storyteller_web/src/routes.rs index 7b5dfcea51..82c263e4d8 100644 --- a/crates/service/web/storyteller_web/src/routes.rs +++ b/crates/service/web/storyteller_web/src/routes.rs @@ -160,6 +160,7 @@ use crate::http_server::endpoints::weights::get_weight::get_weight_handler; use crate::http_server::endpoints::weights::list_available_weights::list_available_weights_handler; use crate::http_server::endpoints::weights::list_featured_weights::list_featured_weights_handler; use crate::http_server::endpoints::weights::list_weights_by_user::list_weights_by_user_handler; +use crate::http_server::endpoints::weights::set_model_weight_avatar::set_model_weight_avatar_handler; use crate::http_server::endpoints::weights::update_weight::update_weight_handler; pub fn add_routes (app: App, server_environment: ServerEnvironment) -> App @@ -1272,12 +1273,13 @@ fn add_weights_routes(app: App) -> App web ::scope("/v1/weights") //.route("/upload", web::post().to(upload_weights_handler)) - .service( - web - ::resource("/weight/{weight_token}") - .route(web::get().to(get_weight_handler)) - .route(web::post().to(update_weight_handler)) - .route(web::delete().to(delete_weight_handler)) + .service(web::resource("/weight/{weight_token}") + .route(web::get().to(get_weight_handler)) + .route(web::post().to(update_weight_handler)) + .route(web::delete().to(delete_weight_handler)) + ) + .service(web::resource("/weight/{token}/avatar") + .route(web::post().to(set_model_weight_avatar_handler)) ) .route("/by_user/{username}", web::get().to(list_weights_by_user_handler)) .route("/list", web::get().to(list_available_weights_handler)) From c627c13e2dc207ab6c2f5b3e52225c0c58c040d3 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Thu, 21 Dec 2023 04:27:45 -0500 Subject: [PATCH 114/124] add creator details --- ...06966bac9f9c420e800d15ce313778272cee.json} | 81 ++++++++++----- ...122342586f4f19a3ac961286c1c54a5c32b2.json} | 99 ++++++++++++------- .../src/queries/model_weights/get_weight.rs | 30 +++++- .../endpoints/weights/get_weight.rs | 28 ++++-- 4 files changed, 170 insertions(+), 68 deletions(-) rename .sqlx/{query-a63aa483bc3a8906a5fa61362534788b757af2dc895b229385101f3b96cd9b51.json => query-4e30e34cdf7a5834a3981d5e634506966bac9f9c420e800d15ce313778272cee.json} (77%) rename .sqlx/{query-a9ee4dedd7375b2baec864892d1358f99f63edacbab6bf4a0c43732884c8f11a.json => query-93084dc42ae4ada186dc90bdd470122342586f4f19a3ac961286c1c54a5c32b2.json} (77%) diff --git a/.sqlx/query-a63aa483bc3a8906a5fa61362534788b757af2dc895b229385101f3b96cd9b51.json b/.sqlx/query-4e30e34cdf7a5834a3981d5e634506966bac9f9c420e800d15ce313778272cee.json similarity index 77% rename from .sqlx/query-a63aa483bc3a8906a5fa61362534788b757af2dc895b229385101f3b96cd9b51.json rename to .sqlx/query-4e30e34cdf7a5834a3981d5e634506966bac9f9c420e800d15ce313778272cee.json index b9439a6d6f..c8fe350ccd 100644 --- a/.sqlx/query-a63aa483bc3a8906a5fa61362534788b757af2dc895b229385101f3b96cd9b51.json +++ b/.sqlx/query-4e30e34cdf7a5834a3981d5e634506966bac9f9c420e800d15ce313778272cee.json @@ -1,6 +1,6 @@ { "db_name": "MySQL", - "query": "\n SELECT\n wt.token as `token: tokens::tokens::model_weights::ModelWeightToken`,\n wt.title,\n wt.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n wt.weights_category as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n wt.maybe_thumbnail_token,\n wt.description_markdown,\n wt.description_rendered_html,\n wt.creator_user_token as `creator_user_token: tokens::tokens::users::UserToken`,\n wt.creator_ip_address,\n wt.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n wt.maybe_last_update_user_token as `maybe_last_update_user_token: tokens::tokens::users::UserToken`,\n wt.original_download_url,\n wt.original_filename,\n wt.file_size_bytes,\n wt.file_checksum_sha2,\n wt.public_bucket_hash,\n wt.maybe_public_bucket_prefix,\n wt.maybe_public_bucket_extension,\n\n avatar.public_bucket_directory_hash as maybe_avatar_public_bucket_hash,\n avatar.maybe_public_bucket_prefix as maybe_avatar_public_bucket_prefix,\n avatar.maybe_public_bucket_extension as maybe_avatar_public_bucket_extension,\n\n wt.cached_user_ratings_negative_count,\n wt.cached_user_ratings_positive_count,\n wt.cached_user_ratings_total_count,\n wt.maybe_cached_user_ratings_ratio,\n wt.cached_user_ratings_last_updated_at,\n wt.version,\n wt.created_at,\n wt.updated_at,\n wt.user_deleted_at,\n wt.mod_deleted_at\n FROM model_weights as wt\n LEFT OUTER JOIN media_files as avatar\n ON avatar.token = wt.maybe_avatar_media_file_token\n WHERE\n wt.token = ?\n ", + "query": "\n SELECT\n wt.token as `token: tokens::tokens::model_weights::ModelWeightToken`,\n wt.title,\n wt.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n wt.weights_category as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n wt.maybe_thumbnail_token,\n wt.description_markdown,\n wt.description_rendered_html,\n\n wt.creator_user_token as `creator_user_token: tokens::tokens::users::UserToken`,\n users.username as creator_username,\n users.display_name as creator_display_name,\n users.email_gravatar_hash AS creator_gravatar_hash,\n\n wt.creator_ip_address,\n wt.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n wt.maybe_last_update_user_token as `maybe_last_update_user_token: tokens::tokens::users::UserToken`,\n wt.original_download_url,\n wt.original_filename,\n wt.file_size_bytes,\n wt.file_checksum_sha2,\n wt.public_bucket_hash,\n wt.maybe_public_bucket_prefix,\n wt.maybe_public_bucket_extension,\n\n avatar.public_bucket_directory_hash as maybe_avatar_public_bucket_hash,\n avatar.maybe_public_bucket_prefix as maybe_avatar_public_bucket_prefix,\n avatar.maybe_public_bucket_extension as maybe_avatar_public_bucket_extension,\n\n wt.cached_user_ratings_negative_count,\n wt.cached_user_ratings_positive_count,\n wt.cached_user_ratings_total_count,\n wt.maybe_cached_user_ratings_ratio,\n wt.cached_user_ratings_last_updated_at,\n wt.version,\n wt.created_at,\n wt.updated_at,\n wt.user_deleted_at,\n wt.mod_deleted_at\n FROM model_weights as wt\n JOIN users\n ON users.token = wt.creator_user_token\n LEFT OUTER JOIN media_files as avatar\n ON avatar.token = wt.maybe_avatar_media_file_token\n WHERE\n wt.token = ?\n ", "describe": { "columns": [ { @@ -85,6 +85,36 @@ }, { "ordinal": 8, + "name": "creator_username", + "type_info": { + "type": "VarString", + "flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 80 + } + }, + { + "ordinal": 9, + "name": "creator_display_name", + "type_info": { + "type": "VarString", + "flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 80 + } + }, + { + "ordinal": 10, + "name": "creator_gravatar_hash", + "type_info": { + "type": "String", + "flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 128 + } + }, + { + "ordinal": 11, "name": "creator_ip_address", "type_info": { "type": "VarString", @@ -94,7 +124,7 @@ } }, { - "ordinal": 9, + "ordinal": 12, "name": "creator_set_visibility: enums::common::visibility::Visibility", "type_info": { "type": "String", @@ -104,7 +134,7 @@ } }, { - "ordinal": 10, + "ordinal": 13, "name": "maybe_last_update_user_token: tokens::tokens::users::UserToken", "type_info": { "type": "VarString", @@ -114,7 +144,7 @@ } }, { - "ordinal": 11, + "ordinal": 14, "name": "original_download_url", "type_info": { "type": "VarString", @@ -124,7 +154,7 @@ } }, { - "ordinal": 12, + "ordinal": 15, "name": "original_filename", "type_info": { "type": "VarString", @@ -134,7 +164,7 @@ } }, { - "ordinal": 13, + "ordinal": 16, "name": "file_size_bytes", "type_info": { "type": "Long", @@ -144,7 +174,7 @@ } }, { - "ordinal": 14, + "ordinal": 17, "name": "file_checksum_sha2", "type_info": { "type": "String", @@ -154,7 +184,7 @@ } }, { - "ordinal": 15, + "ordinal": 18, "name": "public_bucket_hash", "type_info": { "type": "VarString", @@ -164,7 +194,7 @@ } }, { - "ordinal": 16, + "ordinal": 19, "name": "maybe_public_bucket_prefix", "type_info": { "type": "VarString", @@ -174,7 +204,7 @@ } }, { - "ordinal": 17, + "ordinal": 20, "name": "maybe_public_bucket_extension", "type_info": { "type": "VarString", @@ -184,7 +214,7 @@ } }, { - "ordinal": 18, + "ordinal": 21, "name": "maybe_avatar_public_bucket_hash", "type_info": { "type": "VarString", @@ -194,7 +224,7 @@ } }, { - "ordinal": 19, + "ordinal": 22, "name": "maybe_avatar_public_bucket_prefix", "type_info": { "type": "VarString", @@ -204,7 +234,7 @@ } }, { - "ordinal": 20, + "ordinal": 23, "name": "maybe_avatar_public_bucket_extension", "type_info": { "type": "VarString", @@ -214,7 +244,7 @@ } }, { - "ordinal": 21, + "ordinal": 24, "name": "cached_user_ratings_negative_count", "type_info": { "type": "Long", @@ -224,7 +254,7 @@ } }, { - "ordinal": 22, + "ordinal": 25, "name": "cached_user_ratings_positive_count", "type_info": { "type": "Long", @@ -234,7 +264,7 @@ } }, { - "ordinal": 23, + "ordinal": 26, "name": "cached_user_ratings_total_count", "type_info": { "type": "Long", @@ -244,7 +274,7 @@ } }, { - "ordinal": 24, + "ordinal": 27, "name": "maybe_cached_user_ratings_ratio", "type_info": { "type": "Float", @@ -254,7 +284,7 @@ } }, { - "ordinal": 25, + "ordinal": 28, "name": "cached_user_ratings_last_updated_at", "type_info": { "type": "Timestamp", @@ -264,7 +294,7 @@ } }, { - "ordinal": 26, + "ordinal": 29, "name": "version", "type_info": { "type": "Long", @@ -274,7 +304,7 @@ } }, { - "ordinal": 27, + "ordinal": 30, "name": "created_at", "type_info": { "type": "Timestamp", @@ -284,7 +314,7 @@ } }, { - "ordinal": 28, + "ordinal": 31, "name": "updated_at", "type_info": { "type": "Timestamp", @@ -294,7 +324,7 @@ } }, { - "ordinal": 29, + "ordinal": 32, "name": "user_deleted_at", "type_info": { "type": "Timestamp", @@ -304,7 +334,7 @@ } }, { - "ordinal": 30, + "ordinal": 33, "name": "mod_deleted_at", "type_info": { "type": "Timestamp", @@ -328,6 +358,9 @@ false, false, false, + false, + false, + false, true, true, true, @@ -351,5 +384,5 @@ true ] }, - "hash": "a63aa483bc3a8906a5fa61362534788b757af2dc895b229385101f3b96cd9b51" + "hash": "4e30e34cdf7a5834a3981d5e634506966bac9f9c420e800d15ce313778272cee" } diff --git a/.sqlx/query-a9ee4dedd7375b2baec864892d1358f99f63edacbab6bf4a0c43732884c8f11a.json b/.sqlx/query-93084dc42ae4ada186dc90bdd470122342586f4f19a3ac961286c1c54a5c32b2.json similarity index 77% rename from .sqlx/query-a9ee4dedd7375b2baec864892d1358f99f63edacbab6bf4a0c43732884c8f11a.json rename to .sqlx/query-93084dc42ae4ada186dc90bdd470122342586f4f19a3ac961286c1c54a5c32b2.json index af12d367e2..2532a7cc9d 100644 --- a/.sqlx/query-a9ee4dedd7375b2baec864892d1358f99f63edacbab6bf4a0c43732884c8f11a.json +++ b/.sqlx/query-93084dc42ae4ada186dc90bdd470122342586f4f19a3ac961286c1c54a5c32b2.json @@ -1,6 +1,6 @@ { "db_name": "MySQL", - "query": "\n SELECT\n wt.token as `token: tokens::tokens::model_weights::ModelWeightToken`,\n wt.title,\n wt.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n wt.weights_category as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n wt.maybe_thumbnail_token,\n wt.description_markdown,\n wt.description_rendered_html,\n wt.creator_user_token as `creator_user_token: tokens::tokens::users::UserToken`,\n wt.creator_ip_address,\n wt.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n wt.maybe_last_update_user_token as `maybe_last_update_user_token: tokens::tokens::users::UserToken`,\n wt.original_download_url,\n wt.original_filename,\n wt.file_size_bytes,\n wt.file_checksum_sha2,\n wt.public_bucket_hash,\n wt.maybe_public_bucket_prefix,\n wt.maybe_public_bucket_extension,\n\n avatar.public_bucket_directory_hash as maybe_avatar_public_bucket_hash,\n avatar.maybe_public_bucket_prefix as maybe_avatar_public_bucket_prefix,\n avatar.maybe_public_bucket_extension as maybe_avatar_public_bucket_extension,\n\n wt.cached_user_ratings_negative_count,\n wt.cached_user_ratings_positive_count,\n wt.cached_user_ratings_total_count,\n wt.maybe_cached_user_ratings_ratio,\n wt.cached_user_ratings_last_updated_at,\n wt.version,\n wt.created_at,\n wt.updated_at,\n wt.user_deleted_at,\n wt.mod_deleted_at\n FROM model_weights as wt\n LEFT OUTER JOIN media_files as avatar\n ON avatar.token = wt.maybe_avatar_media_file_token\n WHERE\n wt.token = ?\n AND wt.user_deleted_at IS NULL\n AND wt.mod_deleted_at IS NULL\n ", + "query": "\n SELECT\n wt.token as `token: tokens::tokens::model_weights::ModelWeightToken`,\n wt.title,\n wt.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n wt.weights_category as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n wt.maybe_thumbnail_token,\n wt.description_markdown,\n wt.description_rendered_html,\n wt.creator_ip_address,\n wt.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n\n wt.creator_user_token as `creator_user_token: tokens::tokens::users::UserToken`,\n users.username as creator_username,\n users.display_name as creator_display_name,\n users.email_gravatar_hash AS creator_gravatar_hash,\n\n wt.maybe_last_update_user_token as `maybe_last_update_user_token: tokens::tokens::users::UserToken`,\n wt.original_download_url,\n wt.original_filename,\n wt.file_size_bytes,\n wt.file_checksum_sha2,\n wt.public_bucket_hash,\n wt.maybe_public_bucket_prefix,\n wt.maybe_public_bucket_extension,\n\n avatar.public_bucket_directory_hash as maybe_avatar_public_bucket_hash,\n avatar.maybe_public_bucket_prefix as maybe_avatar_public_bucket_prefix,\n avatar.maybe_public_bucket_extension as maybe_avatar_public_bucket_extension,\n\n wt.cached_user_ratings_negative_count,\n wt.cached_user_ratings_positive_count,\n wt.cached_user_ratings_total_count,\n wt.maybe_cached_user_ratings_ratio,\n wt.cached_user_ratings_last_updated_at,\n wt.version,\n wt.created_at,\n wt.updated_at,\n wt.user_deleted_at,\n wt.mod_deleted_at\n FROM model_weights as wt\n JOIN users\n ON users.token = wt.creator_user_token\n LEFT OUTER JOIN media_files as avatar\n ON avatar.token = wt.maybe_avatar_media_file_token\n WHERE\n wt.token = ?\n AND wt.user_deleted_at IS NULL\n AND wt.mod_deleted_at IS NULL\n ", "describe": { "columns": [ { @@ -75,16 +75,6 @@ }, { "ordinal": 7, - "name": "creator_user_token: tokens::tokens::users::UserToken", - "type_info": { - "type": "VarString", - "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE", - "char_set": 224, - "max_size": 128 - } - }, - { - "ordinal": 8, "name": "creator_ip_address", "type_info": { "type": "VarString", @@ -94,7 +84,7 @@ } }, { - "ordinal": 9, + "ordinal": 8, "name": "creator_set_visibility: enums::common::visibility::Visibility", "type_info": { "type": "String", @@ -103,8 +93,48 @@ "max_size": 28 } }, + { + "ordinal": 9, + "name": "creator_user_token: tokens::tokens::users::UserToken", + "type_info": { + "type": "VarString", + "flags": "NOT_NULL | MULTIPLE_KEY | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 128 + } + }, { "ordinal": 10, + "name": "creator_username", + "type_info": { + "type": "VarString", + "flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 80 + } + }, + { + "ordinal": 11, + "name": "creator_display_name", + "type_info": { + "type": "VarString", + "flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 80 + } + }, + { + "ordinal": 12, + "name": "creator_gravatar_hash", + "type_info": { + "type": "String", + "flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE", + "char_set": 224, + "max_size": 128 + } + }, + { + "ordinal": 13, "name": "maybe_last_update_user_token: tokens::tokens::users::UserToken", "type_info": { "type": "VarString", @@ -114,7 +144,7 @@ } }, { - "ordinal": 11, + "ordinal": 14, "name": "original_download_url", "type_info": { "type": "VarString", @@ -124,7 +154,7 @@ } }, { - "ordinal": 12, + "ordinal": 15, "name": "original_filename", "type_info": { "type": "VarString", @@ -134,7 +164,7 @@ } }, { - "ordinal": 13, + "ordinal": 16, "name": "file_size_bytes", "type_info": { "type": "Long", @@ -144,7 +174,7 @@ } }, { - "ordinal": 14, + "ordinal": 17, "name": "file_checksum_sha2", "type_info": { "type": "String", @@ -154,7 +184,7 @@ } }, { - "ordinal": 15, + "ordinal": 18, "name": "public_bucket_hash", "type_info": { "type": "VarString", @@ -164,7 +194,7 @@ } }, { - "ordinal": 16, + "ordinal": 19, "name": "maybe_public_bucket_prefix", "type_info": { "type": "VarString", @@ -174,7 +204,7 @@ } }, { - "ordinal": 17, + "ordinal": 20, "name": "maybe_public_bucket_extension", "type_info": { "type": "VarString", @@ -184,7 +214,7 @@ } }, { - "ordinal": 18, + "ordinal": 21, "name": "maybe_avatar_public_bucket_hash", "type_info": { "type": "VarString", @@ -194,7 +224,7 @@ } }, { - "ordinal": 19, + "ordinal": 22, "name": "maybe_avatar_public_bucket_prefix", "type_info": { "type": "VarString", @@ -204,7 +234,7 @@ } }, { - "ordinal": 20, + "ordinal": 23, "name": "maybe_avatar_public_bucket_extension", "type_info": { "type": "VarString", @@ -214,7 +244,7 @@ } }, { - "ordinal": 21, + "ordinal": 24, "name": "cached_user_ratings_negative_count", "type_info": { "type": "Long", @@ -224,7 +254,7 @@ } }, { - "ordinal": 22, + "ordinal": 25, "name": "cached_user_ratings_positive_count", "type_info": { "type": "Long", @@ -234,7 +264,7 @@ } }, { - "ordinal": 23, + "ordinal": 26, "name": "cached_user_ratings_total_count", "type_info": { "type": "Long", @@ -244,7 +274,7 @@ } }, { - "ordinal": 24, + "ordinal": 27, "name": "maybe_cached_user_ratings_ratio", "type_info": { "type": "Float", @@ -254,7 +284,7 @@ } }, { - "ordinal": 25, + "ordinal": 28, "name": "cached_user_ratings_last_updated_at", "type_info": { "type": "Timestamp", @@ -264,7 +294,7 @@ } }, { - "ordinal": 26, + "ordinal": 29, "name": "version", "type_info": { "type": "Long", @@ -274,7 +304,7 @@ } }, { - "ordinal": 27, + "ordinal": 30, "name": "created_at", "type_info": { "type": "Timestamp", @@ -284,7 +314,7 @@ } }, { - "ordinal": 28, + "ordinal": 31, "name": "updated_at", "type_info": { "type": "Timestamp", @@ -294,7 +324,7 @@ } }, { - "ordinal": 29, + "ordinal": 32, "name": "user_deleted_at", "type_info": { "type": "Timestamp", @@ -304,7 +334,7 @@ } }, { - "ordinal": 30, + "ordinal": 33, "name": "mod_deleted_at", "type_info": { "type": "Timestamp", @@ -328,6 +358,9 @@ false, false, false, + false, + false, + false, true, true, true, @@ -351,5 +384,5 @@ true ] }, - "hash": "a9ee4dedd7375b2baec864892d1358f99f63edacbab6bf4a0c43732884c8f11a" + "hash": "93084dc42ae4ada186dc90bdd470122342586f4f19a3ac961286c1c54a5c32b2" } diff --git a/crates/lib/mysql_queries/src/queries/model_weights/get_weight.rs b/crates/lib/mysql_queries/src/queries/model_weights/get_weight.rs index 7dba007d6c..71efd4fc0d 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/get_weight.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/get_weight.rs @@ -22,9 +22,15 @@ pub struct RetrivedModelWeight { pub maybe_thumbnail_token: Option, pub description_markdown: String, pub description_rendered_html: String, + pub creator_user_token: UserToken, + pub creator_username: String, + pub creator_display_name: String, + pub creator_gravatar_hash: String, + pub creator_ip_address: String, pub creator_set_visibility: Visibility, + pub maybe_last_update_user_token: Option, pub original_download_url: Option, pub original_filename: Option, @@ -93,6 +99,9 @@ pub async fn get_weights_by_token_with_connection( description_markdown: record.description_markdown, description_rendered_html: record.description_rendered_html, creator_user_token: record.creator_user_token, + creator_username: record.creator_username, + creator_display_name: record.creator_display_name, + creator_gravatar_hash: record.creator_gravatar_hash, creator_ip_address: record.creator_ip_address, creator_set_visibility: record.creator_set_visibility, maybe_last_update_user_token: record.maybe_last_update_user_token, @@ -136,7 +145,12 @@ async fn select_include_deleted( wt.maybe_thumbnail_token, wt.description_markdown, wt.description_rendered_html, + wt.creator_user_token as `creator_user_token: tokens::tokens::users::UserToken`, + users.username as creator_username, + users.display_name as creator_display_name, + users.email_gravatar_hash AS creator_gravatar_hash, + wt.creator_ip_address, wt.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`, wt.maybe_last_update_user_token as `maybe_last_update_user_token: tokens::tokens::users::UserToken`, @@ -163,6 +177,8 @@ async fn select_include_deleted( wt.user_deleted_at, wt.mod_deleted_at FROM model_weights as wt + JOIN users + ON users.token = wt.creator_user_token LEFT OUTER JOIN media_files as avatar ON avatar.token = wt.maybe_avatar_media_file_token WHERE @@ -191,9 +207,14 @@ async fn select_without_deleted( wt.maybe_thumbnail_token, wt.description_markdown, wt.description_rendered_html, - wt.creator_user_token as `creator_user_token: tokens::tokens::users::UserToken`, wt.creator_ip_address, wt.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`, + + wt.creator_user_token as `creator_user_token: tokens::tokens::users::UserToken`, + users.username as creator_username, + users.display_name as creator_display_name, + users.email_gravatar_hash AS creator_gravatar_hash, + wt.maybe_last_update_user_token as `maybe_last_update_user_token: tokens::tokens::users::UserToken`, wt.original_download_url, wt.original_filename, @@ -218,6 +239,8 @@ async fn select_without_deleted( wt.user_deleted_at, wt.mod_deleted_at FROM model_weights as wt + JOIN users + ON users.token = wt.creator_user_token LEFT OUTER JOIN media_files as avatar ON avatar.token = wt.maybe_avatar_media_file_token WHERE @@ -240,7 +263,12 @@ pub struct RawWeight { pub maybe_thumbnail_token: Option, pub description_markdown: String, pub description_rendered_html: String, + pub creator_user_token: UserToken, + pub creator_username: String, + pub creator_display_name: String, + pub creator_gravatar_hash: String, + pub creator_ip_address: String, pub creator_set_visibility: Visibility, pub maybe_last_update_user_token: Option, diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/get_weight.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/get_weight.rs index bafc95499e..66980cbc0c 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/get_weight.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/get_weight.rs @@ -1,26 +1,24 @@ use std::fmt; use std::sync::Arc; + use actix_web::{HttpRequest, HttpResponse, web}; use actix_web::error::ResponseError; use actix_web::http::StatusCode; use actix_web::web::Path; use chrono::{DateTime, Utc}; use log::warn; +use utoipa::ToSchema; + +use buckets::public::media_files::bucket_file_path::MediaFileBucketPath; +use enums::by_table::model_weights::weights_category::WeightsCategory; +use enums::by_table::model_weights::weights_types::WeightsType; use enums::common::visibility::Visibility; -use tokens::tokens::users::UserToken; +use mysql_queries::queries::model_weights::get_weight::get_weight_by_token; +use tokens::tokens::model_weights::ModelWeightToken; use crate::http_server::common_responses::user_details_lite::UserDetailsLight; use crate::server_state::ServerState; -use tokens::tokens::model_weights::ModelWeightToken; -use mysql_queries::queries::model_weights::get_weight::get_weight_by_token; - -use enums::by_table::model_weights::weights_types::WeightsType; -use enums::by_table::model_weights::weights_category::WeightsCategory; - -use utoipa::ToSchema; -use buckets::public::media_files::bucket_file_path::MediaFileBucketPath; - #[derive(Serialize, Clone, ToSchema)] pub struct GetWeightResponse { success: bool, @@ -31,6 +29,8 @@ pub struct GetWeightResponse { maybe_thumbnail_token: Option, description_markdown: String, description_rendered_html: String, + + creator: UserDetailsLight, creator_set_visibility: Visibility, file_size_bytes: i32, @@ -154,6 +154,13 @@ pub async fn get_weight_handler( .to_string() }); + let creator = UserDetailsLight::from_db_fields( + &weight.creator_user_token, + &weight.creator_username, + &weight.creator_display_name, + &weight.creator_gravatar_hash, + ); + let response = GetWeightResponse { success: true, weight_token: weight.token, @@ -164,6 +171,7 @@ pub async fn get_weight_handler( description_markdown: weight.description_markdown, description_rendered_html: weight.description_rendered_html, maybe_avatar_public_bucket_path: maybe_avatar, + creator, creator_set_visibility: weight.creator_set_visibility, file_size_bytes: weight.file_size_bytes, file_checksum_sha2: weight.file_checksum_sha2, From 64be9e49af618aec58f8ae8c5fe7048199fcce25 Mon Sep 17 00:00:00 2001 From: Kasisnu <5044120+kasisnu@users.noreply.github.com> Date: Thu, 21 Dec 2023 19:52:44 +0530 Subject: [PATCH 115/124] Document user bookmarks endpoints --- .../user_bookmark_entity_type.rs | 3 +- .../tokens/src/tokens/user_bookmarks.rs | 3 +- .../web/storyteller_web/src/api_doc.rs | 23 +++++++- .../create_user_bookmark_handler.rs | 16 +++++- .../delete_user_bookmark_handler.rs | 21 ++++++- .../list_user_bookmarks_for_entity_handler.rs | 52 ++++++++++------- .../list_user_bookmarks_for_user_handler.rs | 57 ++++++++++++------- 7 files changed, 124 insertions(+), 51 deletions(-) diff --git a/crates/_types/enums/src/by_table/user_bookmarks/user_bookmark_entity_type.rs b/crates/_types/enums/src/by_table/user_bookmarks/user_bookmark_entity_type.rs index 1e3fa6692c..31475b24ef 100644 --- a/crates/_types/enums/src/by_table/user_bookmarks/user_bookmark_entity_type.rs +++ b/crates/_types/enums/src/by_table/user_bookmarks/user_bookmark_entity_type.rs @@ -4,10 +4,11 @@ use serde::Serialize; use strum::EnumCount; #[cfg(test)] use strum::EnumIter; +use utoipa::ToSchema; /// Used in the `user_bookmarks` table in a `VARCHAR(32)` field named `entity_type`. #[cfg_attr(test, derive(EnumIter, EnumCount))] -#[derive(Clone, Copy, Eq, PartialEq, Hash, Deserialize, Serialize)] +#[derive(Clone, Copy, Eq, PartialEq, Hash, Deserialize, Serialize, ToSchema)] pub enum UserBookmarkEntityType { /// User #[serde(rename = "user")] diff --git a/crates/_types/tokens/src/tokens/user_bookmarks.rs b/crates/_types/tokens/src/tokens/user_bookmarks.rs index ac91dc079d..94ec6f99e5 100644 --- a/crates/_types/tokens/src/tokens/user_bookmarks.rs +++ b/crates/_types/tokens/src/tokens/user_bookmarks.rs @@ -2,11 +2,12 @@ use std::fmt::Debug; use serde::Deserialize; use serde::Serialize; +use utoipa::ToSchema; use crate::prefixes::TokenPrefix; /// The primary key for Audit Logs. -#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, sqlx::Type, Debug, Serialize, Deserialize)] +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, sqlx::Type, Debug, Serialize, Deserialize, ToSchema)] #[sqlx(transparent)] pub struct UserBookmarkToken(pub String); diff --git a/crates/service/web/storyteller_web/src/api_doc.rs b/crates/service/web/storyteller_web/src/api_doc.rs index e6808517b7..3e0604480c 100644 --- a/crates/service/web/storyteller_web/src/api_doc.rs +++ b/crates/service/web/storyteller_web/src/api_doc.rs @@ -18,11 +18,21 @@ use enums::by_table::media_files::media_file_type::MediaFileType; use enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory; use enums::by_table::media_files::media_file_origin_model_type::MediaFileOriginModelType; use enums::by_table::media_files::media_file_origin_product_category::MediaFileOriginProductCategory; +use enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType; + +use crate::http_server::endpoints::user_bookmarks::create_user_bookmark_handler::*; +use crate::http_server::endpoints::user_bookmarks::delete_user_bookmark_handler::*; +use crate::http_server::endpoints::user_bookmarks::list_user_bookmarks_for_entity_handler::*; +use crate::http_server::endpoints::user_bookmarks::list_user_bookmarks_for_session_handler::*; +use crate::http_server::endpoints::user_bookmarks::list_user_bookmarks_for_user_handler::*; +use crate::http_server::endpoints::user_ratings::get_user_rating_handler::*; +use crate::http_server::endpoints::user_ratings::set_user_rating_handler::*; use tokens::tokens::generic_inference_jobs::*; use tokens::tokens::model_weights::*; use tokens::tokens::users::*; use tokens::tokens::media_files::*; +use tokens::tokens::user_bookmarks::*; use enums::common::visibility::Visibility; use chrono::{DateTime, Utc}; use utoipa::OpenApi; @@ -36,7 +46,11 @@ use utoipa::OpenApi; crate::http_server::endpoints::weights::list_weights_by_user::list_weights_by_user_handler, crate::http_server::endpoints::media_files::list_featured_media_files::list_featured_media_files_handler, crate::http_server::endpoints::media_files::list_media_files::list_media_files_handler, - crate::http_server::endpoints::media_files::list_media_files_for_user::list_media_files_for_user_handler + crate::http_server::endpoints::media_files::list_media_files_for_user::list_media_files_for_user_handler, + crate::http_server::endpoints::user_bookmarks::create_user_bookmark_handler::create_user_bookmark_handler, + crate::http_server::endpoints::user_bookmarks::delete_user_bookmark_handler::delete_user_bookmark_handler, + crate::http_server::endpoints::user_bookmarks::list_user_bookmarks_for_user_handler::list_user_bookmarks_for_user_handler, + crate::http_server::endpoints::user_bookmarks::list_user_bookmarks_for_entity_handler::list_user_bookmarks_for_entity_handler, ),components(schemas( // Tokens UserToken,Visibility, @@ -60,6 +74,11 @@ use utoipa::OpenApi; ListMediaFilesSuccessResponse, ListMediaFilesError, MediaFileListItem, ListMediaFilesQueryParams, MediaFileSocialMetaLight, ListMediaFilesForUserSuccessResponse,ListMediaFilesForUserQueryParams,ListMediaFilesForUserError,ListMediaFilesForUserPathInfo, - MediaFileForUserListItem, MediaFileForUserListItem + MediaFileForUserListItem, MediaFileForUserListItem, + UserBookmarkToken,UserBookmarkDetailsForUserList,UserBookmarkEntityType, + CreateUserBookmarkRequest,CreateUserBookmarkError,CreateUserBookmarkSuccessResponse, + DeleteUserBookmarkPathInfo,DeleteUserBookmarkError,DeleteUserBookmarkRequest, + ListUserBookmarksPathInfo,ListUserBookmarksForUserError,ListUserBookmarksForUserSuccessResponse,UserBookmarkListItem, + ListUserBookmarksForEntityPathInfo,ListUserBookmarksForEntityError,ListUserBookmarksForEntitySuccessResponse,UserBookmarkForEntityListItem, )))] pub struct ApiDoc; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/create_user_bookmark_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/create_user_bookmark_handler.rs index 43f0fe6ac1..f720c601c7 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/create_user_bookmark_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/create_user_bookmark_handler.rs @@ -10,6 +10,7 @@ use actix_web::{HttpRequest, HttpResponse, web}; use actix_web::error::ResponseError; use actix_web::http::StatusCode; use log::warn; +use utoipa::ToSchema; use enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType; use mysql_queries::queries::user_bookmarks::create_user_bookmark::{create_user_bookmark, CreateUserBookmarkArgs}; @@ -28,19 +29,19 @@ use tokens::tokens::zs_voices::ZsVoiceToken; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; use crate::server_state::ServerState; -#[derive(Deserialize)] +#[derive(Deserialize, ToSchema)] pub struct CreateUserBookmarkRequest { entity_token: String, entity_type: UserBookmarkEntityType, } -#[derive(Serialize)] +#[derive(Serialize, ToSchema)] pub struct CreateUserBookmarkSuccessResponse { pub success: bool, pub user_bookmark_token: UserBookmarkToken, } -#[derive(Debug)] +#[derive(Debug, ToSchema)] pub enum CreateUserBookmarkError { BadInput(String), NotAuthorized, @@ -74,6 +75,15 @@ impl fmt::Display for CreateUserBookmarkError { } } +#[utoipa::path( +post, +path = "/v1/user_bookmarks/create", +request_body = CreateUserBookmarkRequest, +responses( +(status = 200, body = CreateUserBookmarkSuccessResponse), +(status = 400, body = CreateUserBookmarkError), +) +)] pub async fn create_user_bookmark_handler( http_request: HttpRequest, request: web::Json, diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/delete_user_bookmark_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/delete_user_bookmark_handler.rs index d68fc29e75..d449bb78f5 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/delete_user_bookmark_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/delete_user_bookmark_handler.rs @@ -11,6 +11,7 @@ use actix_web::error::ResponseError; use actix_web::http::StatusCode; use actix_web::web::Path; use log::warn; +use utoipa::ToSchema; use mysql_queries::queries::user_bookmarks::delete_user_bookmark::delete_user_bookmark; use tokens::tokens::user_bookmarks::UserBookmarkToken; @@ -20,18 +21,18 @@ use crate::http_server::web_utils::response_success_helpers::simple_json_success use crate::server_state::ServerState; /// For the URL PathInfo -#[derive(Deserialize)] +#[derive(Deserialize, ToSchema)] pub struct DeleteUserBookmarkPathInfo { user_bookmark_token: UserBookmarkToken, } -#[derive(Deserialize)] +#[derive(Deserialize, ToSchema)] pub struct DeleteUserBookmarkRequest { /// NB: this is only to disambiguate when a user is both a mod and an author. as_mod: Option, } -#[derive(Debug)] +#[derive(Debug, ToSchema)] pub enum DeleteUserBookmarkError { BadInput(String), NotAuthorized, @@ -68,6 +69,20 @@ impl fmt::Display for DeleteUserBookmarkError { } } +#[utoipa::path( + delete, + path = "/v1/user_bookmarks/delete/{user_bookmark_token}", + params( + ("user_bookmark_token", description = "UserBookmarkToken"), + ), + responses( + (status = 200, description = "Delete User Bookmark", body = SimpleGenericJsonSuccess), + (status = 400, description = "Bad input", body = DeleteUserBookmarkError), + (status = 401, description = "Not authorized", body = DeleteUserBookmarkError), + (status = 404, description = "Not found", body = DeleteUserBookmarkError), + (status = 500, description = "Server error", body = DeleteUserBookmarkError), + ), +)] pub async fn delete_user_bookmark_handler( http_request: HttpRequest, path: Path, diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/list_user_bookmarks_for_entity_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/list_user_bookmarks_for_entity_handler.rs index 0fa28887fd..abeb7fa0ca 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/list_user_bookmarks_for_entity_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/list_user_bookmarks_for_entity_handler.rs @@ -12,6 +12,7 @@ use actix_web::http::StatusCode; use actix_web::web::Path; use chrono::{DateTime, Utc}; use log::warn; +use utoipa::ToSchema; use enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType; use mysql_queries::queries::user_bookmarks::user_bookmark_entity_token::UserBookmarkEntityToken; @@ -23,20 +24,20 @@ use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; use crate::server_state::ServerState; /// For the URL PathInfo -#[derive(Deserialize)] -pub struct ListUserBookmarkPathInfo { +#[derive(Deserialize, ToSchema)] +pub struct ListUserBookmarksForEntityPathInfo { entity_type: UserBookmarkEntityType, entity_token: String, } -#[derive(Serialize)] -pub struct ListUserBookmarksSuccessResponse { +#[derive(Serialize, ToSchema)] +pub struct ListUserBookmarksForEntitySuccessResponse { pub success: bool, - pub user_bookmarks: Vec, + pub user_bookmarks: Vec, } -#[derive(Serialize)] -pub struct UserBookmark { +#[derive(Serialize, ToSchema)] +pub struct UserBookmarkForEntityListItem { pub token: UserBookmarkToken, pub user: UserDetailsLight, @@ -45,21 +46,21 @@ pub struct UserBookmark { pub updated_at: DateTime, } -#[derive(Debug)] -pub enum ListUserBookmarksError { +#[derive(Debug, ToSchema)] +pub enum ListUserBookmarksForEntityError { ServerError, } -impl ResponseError for ListUserBookmarksError { +impl ResponseError for ListUserBookmarksForEntityError { fn status_code(&self) -> StatusCode { match *self { - ListUserBookmarksError::ServerError=> StatusCode::INTERNAL_SERVER_ERROR, + ListUserBookmarksForEntityError::ServerError=> StatusCode::INTERNAL_SERVER_ERROR, } } fn error_response(&self) -> HttpResponse { let error_reason = match self { - ListUserBookmarksError::ServerError => "server error".to_string(), + ListUserBookmarksForEntityError::ServerError => "server error".to_string(), }; to_simple_json_error(&error_reason, self.status_code()) @@ -67,17 +68,30 @@ impl ResponseError for ListUserBookmarksError { } // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for ListUserBookmarksError { +impl fmt::Display for ListUserBookmarksForEntityError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:?}", self) } } + +#[utoipa::path( + get, + path = "/v1/user_bookmarks/list/{entity_type}/{entity_token}", + params( + ("entity_type", description="The type of entity to list bookmarks for"), + ("entity_token", description="The token of the entity to list bookmarks for"), + ), + responses( + (status = 200, body = ListUserBookmarksForEntitySuccessResponse), + (status = 500, body = ListUserBookmarksForEntityError), + ), +)] pub async fn list_user_bookmarks_for_entity_handler( _http_request: HttpRequest, - path: Path, + path: Path, server_state: web::Data> -) -> Result +) -> Result { let entity_token = UserBookmarkEntityToken::from_entity_type_and_token( path.entity_type, &path.entity_token); @@ -91,14 +105,14 @@ pub async fn list_user_bookmarks_for_entity_handler( Ok(results) => results, Err(e) => { warn!("Query error: {:?}", e); - return Err(ListUserBookmarksError::ServerError); + return Err(ListUserBookmarksForEntityError::ServerError); } }; - let response = ListUserBookmarksSuccessResponse { + let response = ListUserBookmarksForEntitySuccessResponse { success: true, user_bookmarks: user_bookmarks.into_iter() - .map(|user_bookmark| UserBookmark { + .map(|user_bookmark| UserBookmarkForEntityListItem { token: user_bookmark.token, user: UserDetailsLight { user_token: user_bookmark.user_token.clone(), @@ -114,7 +128,7 @@ pub async fn list_user_bookmarks_for_entity_handler( }; let body = serde_json::to_string(&response) - .map_err(|_e| ListUserBookmarksError::ServerError)?; + .map_err(|_e| ListUserBookmarksForEntityError::ServerError)?; Ok(HttpResponse::Ok() .content_type("application/json") diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/list_user_bookmarks_for_user_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/list_user_bookmarks_for_user_handler.rs index ccaf8b61f4..3118d490d1 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/list_user_bookmarks_for_user_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/user_bookmarks/list_user_bookmarks_for_user_handler.rs @@ -12,6 +12,7 @@ use actix_web::http::StatusCode; use actix_web::web::{Path, Query}; use chrono::{DateTime, Utc}; use log::warn; +use utoipa::{IntoParams, ToSchema}; use enums::by_table::user_bookmarks::user_bookmark_entity_type::UserBookmarkEntityType; use mysql_queries::queries::user_bookmarks::list_user_bookmarks::{list_user_bookmarks, list_user_user_bookmarks_by_entity_type}; @@ -20,34 +21,34 @@ use tokens::tokens::user_bookmarks::UserBookmarkToken; use crate::http_server::web_utils::response_error_helpers::to_simple_json_error; use crate::server_state::ServerState; -#[derive(Deserialize)] +#[derive(Deserialize, ToSchema)] pub struct ListUserBookmarksPathInfo { username: String, } -#[derive(Deserialize)] +#[derive(Deserialize, ToSchema, IntoParams)] pub struct ListUserBookmarksQueryData { maybe_scoped_entity_type: Option, } -#[derive(Serialize)] -pub struct ListUserBookmarksSuccessResponse { +#[derive(Serialize, ToSchema)] +pub struct ListUserBookmarksForUserSuccessResponse { pub success: bool, - pub user_bookmarks: Vec, + pub user_bookmarks: Vec, } -#[derive(Serialize)] -pub struct UserBookmark { +#[derive(Serialize, ToSchema)] +pub struct UserBookmarkListItem { pub token: UserBookmarkToken, - pub details: UserBookmarkDetails, + pub details: UserBookmarkDetailsForUserList, pub created_at: DateTime, pub updated_at: DateTime, } -#[derive(Serialize)] -pub struct UserBookmarkDetails { +#[derive(Serialize, ToSchema)] +pub struct UserBookmarkDetailsForUserList { // TODO: This needs titles or some other summary metadata. pub entity_type: UserBookmarkEntityType, pub entity_token: String, @@ -59,21 +60,21 @@ pub struct UserBookmarkDetails { pub maybe_thumbnail_url: Option, } -#[derive(Debug)] -pub enum ListUserBookmarksError { +#[derive(Debug, ToSchema)] +pub enum ListUserBookmarksForUserError { ServerError, } -impl ResponseError for ListUserBookmarksError { +impl ResponseError for ListUserBookmarksForUserError { fn status_code(&self) -> StatusCode { match *self { - ListUserBookmarksError::ServerError=> StatusCode::INTERNAL_SERVER_ERROR, + ListUserBookmarksForUserError::ServerError=> StatusCode::INTERNAL_SERVER_ERROR, } } fn error_response(&self) -> HttpResponse { let error_reason = match self { - ListUserBookmarksError::ServerError => "server error".to_string(), + ListUserBookmarksForUserError::ServerError => "server error".to_string(), }; to_simple_json_error(&error_reason, self.status_code()) @@ -81,18 +82,30 @@ impl ResponseError for ListUserBookmarksError { } // NB: Not using derive_more::Display since Clion doesn't understand it. -impl fmt::Display for ListUserBookmarksError { +impl fmt::Display for ListUserBookmarksForUserError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:?}", self) } } +#[utoipa::path( + get, + path = "/v1/user_bookmarks/list/user/{username}", + params( + ("username", description = "The username of the user whose bookmarks to list."), + ListUserBookmarksQueryData + ), +responses( + (status = 200, description = "List User Bookmarks", body = ListUserBookmarksForUserSuccessResponse), + (status = 500, description = "Server error", body = ListUserBookmarksForUserError), +), +)] pub async fn list_user_bookmarks_for_user_handler( _http_request: HttpRequest, path: Path, query: Query, server_state: web::Data> -) -> Result +) -> Result { let query_results = match query.maybe_scoped_entity_type { @@ -106,16 +119,16 @@ pub async fn list_user_bookmarks_for_user_handler( Ok(results) => results, Err(e) => { warn!("Query error: {:?}", e); - return Err(ListUserBookmarksError::ServerError); + return Err(ListUserBookmarksForUserError::ServerError); } }; - let response = ListUserBookmarksSuccessResponse { + let response = ListUserBookmarksForUserSuccessResponse { success: true, user_bookmarks: user_bookmarks.into_iter() - .map(|user_bookmark| UserBookmark { + .map(|user_bookmark| UserBookmarkListItem { token: user_bookmark.token, - details: UserBookmarkDetails { + details: UserBookmarkDetailsForUserList { entity_type: user_bookmark.entity_type, entity_token: user_bookmark.entity_token, maybe_summary_text: user_bookmark.maybe_entity_descriptive_text, @@ -130,7 +143,7 @@ pub async fn list_user_bookmarks_for_user_handler( }; let body = serde_json::to_string(&response) - .map_err(|_e| ListUserBookmarksError::ServerError)?; + .map_err(|_e| ListUserBookmarksForUserError::ServerError)?; Ok(HttpResponse::Ok() .content_type("application/json") From cbb950cb405531ea94b3a0ea1a19595827bc2e34 Mon Sep 17 00:00:00 2001 From: Brooks Palin Date: Thu, 21 Dec 2023 10:30:36 -0700 Subject: [PATCH 116/124] Update general_setup.md Fixed path for for storyteller-web --- _develop/docs/local_development/general_setup.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_develop/docs/local_development/general_setup.md b/_develop/docs/local_development/general_setup.md index 25c499e0c4..6464f1aae3 100644 --- a/_develop/docs/local_development/general_setup.md +++ b/_develop/docs/local_development/general_setup.md @@ -310,7 +310,7 @@ Secrets: - Put `.env-secrets` in the root `storyteller-rust` directory. - Per app secrets (ask Brandon for these): - - Put `storteller-web.development-secrets.env` in `crates/service/web/storyteller-web/config` + - Put `storteller-web.development-secrets.env` in `crates/service/web/storyteller_web/config` - Put `inference-job.development-secrets.env` in `crates/service/job/inference_job/config` - Put `donwload-job.development-secrets.env` in `crates/service/job/download_job/config` @@ -392,4 +392,4 @@ We use this: `https://github.com/juhaku/utoipa` The documentation example is in: `crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/inference/enqueue_tts_request.rs` Write into the api doc to: -`crates/service/web/storyteller_web/src/api_doc.rs` \ No newline at end of file +`crates/service/web/storyteller_web/src/api_doc.rs` From 0efe2d81774e1d58a9d96a3aa267554172687799 Mon Sep 17 00:00:00 2001 From: Michael Chung Date: Thu, 21 Dec 2023 12:38:04 -0500 Subject: [PATCH 117/124] Working Tests --- .../bucket_orchestration.rs | 85 ++++++------ .../remote_cloud_bucket_details.rs | 6 +- .../remote_cloud_file_manager.rs | 125 +++++++++++++----- .../bucket_orchestration_mock.rs | 3 - 4 files changed, 130 insertions(+), 89 deletions(-) diff --git a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/bucket_orchestration.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/bucket_orchestration.rs index 3641348d65..3ecc452e99 100644 --- a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/bucket_orchestration.rs +++ b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/bucket_orchestration.rs @@ -7,22 +7,20 @@ use errors::AnyhowResult; use crate::bucket_client::BucketClient; #[async_trait] -pub trait BucketOrchestrationDownload { - async fn download_file_to_disk( +pub trait BucketOrchestrationCore { + async fn download_file_to_disk( &self, object_path: String, filesystem_path: String, - is_public:bool + is_public: bool, ) -> AnyhowResult<()>; + + async fn upload_file_with_content_type_process(&self, object_name: &str, + bytes: &[u8], + content_type: &str, + is_public: bool) -> AnyhowResult<()>; } -#[async_trait] -pub trait BucketOrchestrationUpload { - async fn upload_file_with_content_type_process(&self,object_name: &str, - bytes: &[u8], - content_type: &str, - is_public:bool) -> AnyhowResult<()>; -} pub struct BucketOrchestration { access_key: String, @@ -33,41 +31,35 @@ pub struct BucketOrchestration { } #[async_trait] -impl BucketOrchestrationDownload for BucketOrchestration { - - async fn download_file_to_disk( +impl BucketOrchestrationCore for BucketOrchestration { + async fn download_file_to_disk( &self, object_path: String, filesystem_path: String, - is_public:bool + is_public: bool, ) -> AnyhowResult<()> { let bucket_client = self.get_bucket_with_visbility(is_public).await?; bucket_client.download_file_to_disk(object_path, filesystem_path).await } -} -#[async_trait] - impl BucketOrchestrationUpload for BucketOrchestration { - - async fn upload_file_with_content_type_process(&self,object_name: &str, - bytes: &[u8], - content_type: &str, - is_public:bool) -> AnyhowResult<()> { + async fn upload_file_with_content_type_process(&self, object_name: &str, + bytes: &[u8], + content_type: &str, + is_public: bool) -> AnyhowResult<()> { let bucket_client = self.get_bucket_with_visbility(is_public).await?; bucket_client.upload_file_with_content_type_process( object_name, bytes, - content_type + content_type, ).await } } impl BucketOrchestration { - pub fn new_bucket_client_from_existing_env()-> AnyhowResult { - + pub fn new_bucket_client_from_existing_env() -> AnyhowResult { let access_key = easyenv::get_env_string_required("ACCESS_KEY")?; let secret_key = easyenv::get_env_string_required("SECRET_KEY")?; - + let region_name = easyenv::get_env_string_required("REGION_NAME")?; let public_bucket_name = easyenv::get_env_string_required("PUBLIC_BUCKET_NAME")?; let private_bucket_name = easyenv::get_env_string_required("PRIVATE_BUCKET_NAME")?; @@ -78,7 +70,7 @@ impl BucketOrchestration { secret_key, region_name, public_bucket_name, - private_bucket_name + private_bucket_name, ); Ok(bucket_orchestration) @@ -100,41 +92,38 @@ impl BucketOrchestration { } - async fn get_bucket_with_visbility(&self, public:bool) -> AnyhowResult { - + async fn get_bucket_with_visbility(&self, public: bool) -> AnyhowResult { let bucket_timeout = easyenv::get_env_duration_seconds_or_default( - "BUCKET_TIMEOUT_SECONDS", Duration::from_secs(60 * 10)); - let bucket_client:BucketClient; + "BUCKET_TIMEOUT_SECONDS", Duration::from_secs(60 * 10)); + let bucket_client: BucketClient; if public { // use public bucket client info!("Configuring public GCS bucket..."); bucket_client = BucketClient::create( - &self.access_key, - &self.secret_key, - &self.region_name, - &self.public_bucket_name, - None, - Some(bucket_timeout), + &self.access_key, + &self.secret_key, + &self.region_name, + &self.public_bucket_name, + None, + Some(bucket_timeout), )?; - } else { + } else { info!("Configuring private GCS bucket..."); bucket_client = BucketClient::create( - &self.access_key, - &self.secret_key, - &self.region_name, - &self.private_bucket_name, - None, - Some(bucket_timeout), + &self.access_key, + &self.secret_key, + &self.region_name, + &self.private_bucket_name, + None, + Some(bucket_timeout), )?; } Ok(bucket_client) } - } #[cfg(test)] mod tests { - - #[test] - pub fn test() {} + #[test] + pub fn test() {} } \ No newline at end of file diff --git a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_bucket_details.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_bucket_details.rs index e63d4e2270..28cbe1c993 100644 --- a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_bucket_details.rs +++ b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_bucket_details.rs @@ -4,9 +4,9 @@ use super::file_descriptor::FileDescriptor; use crate::remote_file_manager::weights_descriptor::{WeightsLoRADescriptor, WeightsSD15Descriptor, WeightsSDXLDescriptor, self}; pub struct RemoteCloudBucketDetails { - object_hash: String, - prefix: String, - suffix: String, + pub object_hash: String, + pub prefix: String, + pub suffix: String, } impl RemoteCloudBucketDetails { diff --git a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_file_manager.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_file_manager.rs index dd472cbd78..3d2dff3fdf 100644 --- a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_file_manager.rs +++ b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_file_manager.rs @@ -4,35 +4,28 @@ use crate::remote_file_manager::file_directory::FileBucketDirectory; use crate::remote_file_manager::remote_cloud_bucket_details::RemoteCloudBucketDetails; use super::bucket_orchestration; -use super::file_descriptor::{FileDescriptor, self}; +use super::file_descriptor::{FileDescriptor}; use super::file_meta_data::FileMetaData; -use std::time::Duration; -use buckets::public::{public_path, self}; use errors:: AnyhowResult; use filesys::file_read_bytes::file_read_bytes; use filesys::file_size::file_size; -use filesys::path_to_string::path_to_string; + use hashing::sha256::sha256_hash_file::sha256_hash_file; use mimetypes::mimetype_for_bytes::get_mimetype_for_bytes; -use mimetypes::mimetype_for_file::{get_mimetype_for_file, self}; -use log::info; -use storyteller_root::get_seed_tool_data_root; -use std::path::Path; -use bucket_orchestration::BucketOrchestration; -use crate::remote_file_manager::bucket_orchestration::{BucketOrchestrationDownload, BucketOrchestrationUpload}; +use crate::remote_file_manager::bucket_orchestration::{BucketOrchestrationCore}; struct RemoteCloudFileClient { - bucket_orchestration_client: BucketOrchestration + bucket_orchestration_client: Box } impl RemoteCloudFileClient { - pub fn new(bucket_orchestration_client: BucketOrchestration) -> Self { + pub fn new(bucket_orchestration_client: Box) -> Self { Self { bucket_orchestration_client: bucket_orchestration_client } @@ -44,7 +37,6 @@ impl RemoteCloudFileClient { let full_remote_cloud_file_path = file_bucket_directory.get_full_remote_cloud_file_path().to_string(); let is_public = file_descriptor.is_public().clone(); - self.bucket_orchestration_client.download_file_to_disk(full_remote_cloud_file_path, to_system_file_path, is_public).await?; Ok(()) } @@ -94,7 +86,41 @@ impl RemoteCloudFileClient { #[cfg(test)] mod tests { use env_logger; + use errors::AnyhowResult; + use crate::remote_file_manager::bucket_orchestration::BucketOrchestrationCore; use crate::remote_file_manager::weights_descriptor::{WeightsLoRADescriptor, WeightsSD15Descriptor, WeightsSDXLDescriptor}; + use super::bucket_orchestration; + + + struct BucketOrchestrationMock { + + } + #[async-trait] + impl BucketOrchestrationCore for BucketOrchestrationMock { + async fn download_file_to_disk( + &self, + object_path: String, + filesystem_path: String, + is_public: bool, + ) -> AnyhowResult<()>{ + println!("Download File to Disk"); + println!("{}",object_path); + println!("{}",filesystem_path); + println!("{}",is_public); + Ok(()) + } + async fn upload_file_with_content_type_process(&self, object_name: &str, + bytes: &[u8], + content_type: &str, + is_public: bool) -> AnyhowResult<()> { + println!("Upload File to Disk"); + println!("{}",object_name); + println!("{}",content_type); + println!("{}",is_public); + Ok(()) + } + } + #[tokio::test] async fn remote_file_manager_descriptor_test() { @@ -105,41 +131,70 @@ mod tests { assert_eq!(file_descriptor.get_prefix(), "loRA"); assert_eq!(file_descriptor.get_suffix(), "safetensors"); assert_eq!(file_descriptor.is_public(), false); + } #[tokio::test] async fn remote_file_manager_download_existing_file() { use super::*; - //std::env::set_var(TEST_STORYTELLER_ROOT, "/testing/storyteller/root"); + env_logger::init(); - // assert_eq!(get_storyteller_root(), PathBuf::from("/testing/storyteller/root")); - // std::env::remove_var(TEST_STORYTELLER_ROOT); - // let access_key = easyenv::get_env_string_required("ACCESS_KEY")?; - // let secret_key = easyenv::get_env_string_required("SECRET_KEY")?; - // let region_name = easyenv::get_env_string_required("REGION_NAME")?; - // let public_bucket_name = easyenv::get_env_string_required("PUBLIC_BUCKET_NAME")?; - // let private_bucket_name = easyenv::get_env_string_required("PRIVATE_BUCKET_NAME")?; + let file_path:&str= "./file_path_here"; + + // let seed_tool_data_root = get_seed_tool_data_root(); + // let file_path = seed_tool_data_root.join(file_path); + let file_path = file_path.to_str().unwrap(); + let remote_cloud_file_manager = RemoteCloudFileClient { + bucket_orchestration_client: Box::new(BucketOrchestrationCore {}) + }; + + println!("begin upload from file_path: {:?}", file_path); + let details = RemoteCloudBucketDetails { + object_hash: String::from("123"), + prefix: String::from("loRA"), + suffix: String::from("safetensors") + }; + let result = remote_cloud_file_manager.download_file(details,file_path).await; + + match result { + Ok(file_meta_data) => { + println!("file_meta_data: {:?}", file_meta_data); + }, + Err(e) => { + println!("error: {:?}", e); + } + } + } + + #[tokio::test] + async fn remote_file_manager_upload_existing_file() { + use super::*; env_logger::init(); - // let weight_path:&str= "models/imagegen/loRA/nijiMecha.safetensors"; + let weight_path:&str= "models/imagegen/loRA/nijiMecha.safetensors"; // let seed_tool_data_root = get_seed_tool_data_root(); // let weight_path = seed_tool_data_root.join(weight_path); - // let weight_path = weight_path.to_str().unwrap(); + let weight_path = weight_path.to_str().unwrap(); + let remote_cloud_file_manager = RemoteCloudFileClient { + bucket_orchestration_client: Box::new(BucketOrchestrationCore {}) + }; - // println!("begin upload from weight_path: {:?}", weight_path); - // let result = remote_cloud_file_manager.upload_file(Box::new(WeightsLoRADescriptor {}),weight_path).await; - - // match result { - // Ok(file_meta_data) => { - // println!("file_meta_data: {:?}", file_meta_data); - // }, - // Err(e) => { - // println!("error: {:?}", e); - // } - // } - + println!("begin upload from weight_path: {:?}", weight_path); + + let result = remote_cloud_file_manager.upload_file(Box::new(WeightsLoRADescriptor {}),weight_path).await; + + match result { + Ok(file_meta_data) => { + println!("file_meta_data: {:?}", file_meta_data); + }, + Err(e) => { + println!("error: {:?}", e); + } + } } + + } \ No newline at end of file diff --git a/crates/lib/api_clients/cloud_storage/src/remote_file_manager_mock/bucket_orchestration_mock.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager_mock/bucket_orchestration_mock.rs index d7b13b677a..139597f9cb 100644 --- a/crates/lib/api_clients/cloud_storage/src/remote_file_manager_mock/bucket_orchestration_mock.rs +++ b/crates/lib/api_clients/cloud_storage/src/remote_file_manager_mock/bucket_orchestration_mock.rs @@ -1,5 +1,2 @@ - -struct BucketOrchestrationMock { -} \ No newline at end of file From 58181b32cf8edfa7c4dc6381fa3c8090b5465435 Mon Sep 17 00:00:00 2001 From: Kasisnu <5044120+kasisnu@users.noreply.github.com> Date: Fri, 22 Dec 2023 00:43:59 +0530 Subject: [PATCH 118/124] use public pagination for profile weights list endpoint --- .../list/list_media_files_for_user.rs | 1 - .../model_weights/list_weights_by_user.rs | 254 +++++++++++------- .../media_files/list_media_files_for_user.rs | 2 - .../endpoints/weights/list_weights_by_user.rs | 46 +++- 4 files changed, 199 insertions(+), 104 deletions(-) diff --git a/crates/lib/mysql_queries/src/queries/media_files/list/list_media_files_for_user.rs b/crates/lib/mysql_queries/src/queries/media_files/list/list_media_files_for_user.rs index cfe474efbf..2f1cf77ef5 100644 --- a/crates/lib/mysql_queries/src/queries/media_files/list/list_media_files_for_user.rs +++ b/crates/lib/mysql_queries/src/queries/media_files/list/list_media_files_for_user.rs @@ -57,7 +57,6 @@ pub struct ListMediaFileForUserArgs<'a> { } pub async fn list_media_files_for_user(args: ListMediaFileForUserArgs<'_>) -> AnyhowResult { - /// Let's figure out how many results we could have returned total let count_fields = select_total_count_field(); let mut count_query_builder = query_builder( diff --git a/crates/lib/mysql_queries/src/queries/model_weights/list_weights_by_user.rs b/crates/lib/mysql_queries/src/queries/model_weights/list_weights_by_user.rs index 3d069b1a09..00ec55a5a5 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/list_weights_by_user.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/list_weights_by_user.rs @@ -1,15 +1,28 @@ use chrono::{DateTime, Utc}; -use sqlx::{Acquire, MySqlConnection, MySqlPool}; +use sqlx::{Acquire, FromRow, MySql, MySqlConnection, MySqlPool, QueryBuilder, Row}; +use sqlx::mysql::MySqlRow; use enums::by_table::model_weights::{ weights_category::WeightsCategory, weights_types::WeightsType, }; use enums::common::visibility::Visibility; +use enums::traits::mysql_from_row::MySqlFromRow; use errors::AnyhowResult; use tokens::tokens::model_weights::ModelWeightToken; use tokens::tokens::users::UserToken; + +pub struct WeightsForUserListPage { + pub records: Vec, + + pub sort_ascending: bool, + + pub current_page: usize, + pub total_page_count: usize, +} + + #[derive(Serialize)] pub struct WeightsJoinUserRecord { pub token: ModelWeightToken, @@ -59,47 +72,83 @@ pub struct WeightsJoinUserRecord { pub creator_email_gravatar_hash: String, } -pub async fn list_weights_by_creator_username( - mysql_pool: &MySqlPool, - creator_username: &str, - can_see_deleted: bool -) -> AnyhowResult> { - - let mut connection = mysql_pool.acquire().await?; - - let raw_weights: Vec = get_raw_weights_by_creator_username(&mut connection, creator_username, can_see_deleted).await?; - let weights_records: Vec = map_to_weights(raw_weights).await; - - Ok(weights_records) +pub struct ListWeightsForUserArgs<'a> { + pub creator_username: &'a str, + pub page_size: usize, + pub page_index: usize, + pub sort_ascending: bool, + pub can_see_deleted: bool, + pub mysql_pool: &'a MySqlPool, } -async fn get_raw_weights_by_creator_username( - connection: &mut MySqlConnection, - creator_username: &str, - can_see_deleted: bool -) -> AnyhowResult> { +pub async fn list_weights_by_creator_username(args: ListWeightsForUserArgs<'_>) -> AnyhowResult { + let count_fields = select_total_count_field(); + let mut count_query_builder = query_builder( + args.creator_username, + false, + 0, + 0, + args.sort_ascending, + count_fields.as_str(), + args.can_see_deleted, + ); - let connection = connection.acquire().await?; - - if can_see_deleted { - let raw_weights: Vec = sqlx::query_as!( - RawWeightJoinUser, - r#" - SELECT - mw.token as `token: tokens::tokens::model_weights::ModelWeightToken`, + let row_count_query = count_query_builder.build_query_scalar::(); + let row_count_result = row_count_query.fetch_one(args.mysql_pool).await?; + + /// Now fetch the actual results with all the fields + let result_fields = select_result_fields(); + let mut query = query_builder( + args.creator_username, + true, + args.page_index, + args.page_size, + args.sort_ascending, + result_fields.as_str(), + args.can_see_deleted, + ); + + let query = query.build_query_as::(); + let results = query.fetch_all(args.mysql_pool).await?; + + let number_of_pages = (row_count_result / args.page_size as i64) as usize; + + + + let weights_records: Vec = map_to_weights(results).await; + + + Ok(WeightsForUserListPage { + records: weights_records, + sort_ascending: args.sort_ascending, + current_page: args.page_index, + total_page_count: number_of_pages, + }) +} + +fn select_total_count_field() -> String { + r#" + COUNT(mw.id) AS total_count + "# + .to_string() +} + +fn select_result_fields() -> String { + r#" + mw.token, mw.title, - mw.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`, - mw.weights_category as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`, + mw.weights_type, + mw.weights_category, mw.maybe_thumbnail_token, mw.description_markdown, mw.description_rendered_html, - users.token as `creator_user_token: tokens::tokens::users::UserToken`, - users.username as creator_username, - users.display_name as creator_display_name, - users.email_gravatar_hash as creator_email_gravatar_hash, + u.token as creator_user_token, + u.username as creator_username, + u.display_name as creator_display_name, + u.email_gravatar_hash as creator_email_gravatar_hash, mw.creator_ip_address, - mw.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`, - mw.maybe_last_update_user_token as `maybe_last_update_user_token: tokens::tokens::users::UserToken`, + mw.creator_set_visibility, + mw.maybe_last_update_user_token, mw.original_download_url, mw.original_filename, mw.file_size_bytes, @@ -117,65 +166,53 @@ async fn get_raw_weights_by_creator_username( mw.updated_at, mw.user_deleted_at, mw.mod_deleted_at - FROM model_weights as mw - JOIN users - ON users.token = mw.creator_user_token - WHERE - users.username = ? - "#, - creator_username).fetch_all(connection) - .await?; - Ok(raw_weights) - } else { - let raw_weights: Vec = sqlx::query_as!( - RawWeightJoinUser, - r#" - SELECT - mw.token as `token: tokens::tokens::model_weights::ModelWeightToken`, - mw.title, - mw.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`, - mw.weights_category as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`, - mw.maybe_thumbnail_token, - mw.description_markdown, - mw.description_rendered_html, - users.token as `creator_user_token: tokens::tokens::users::UserToken`, - users.username as creator_username, - users.display_name as creator_display_name, - users.email_gravatar_hash as creator_email_gravatar_hash, - mw.creator_ip_address, - mw.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`, - mw.maybe_last_update_user_token as `maybe_last_update_user_token: tokens::tokens::users::UserToken`, - mw.original_download_url, - mw.original_filename, - mw.file_size_bytes, - mw.file_checksum_sha2, - mw.public_bucket_hash, - mw.maybe_public_bucket_prefix, - mw.maybe_public_bucket_extension, - mw.cached_user_ratings_negative_count, - mw.cached_user_ratings_positive_count, - mw.cached_user_ratings_total_count, - mw.maybe_cached_user_ratings_ratio, - mw.cached_user_ratings_last_updated_at, - mw.version, - mw.created_at, - mw.updated_at, - mw.user_deleted_at, - mw.mod_deleted_at - FROM model_weights as mw - JOIN users - ON users.token = mw.creator_user_token - WHERE - users.username = ? - AND mw.user_deleted_at IS NULL - AND mw.mod_deleted_at IS NULL - "#, - creator_username).fetch_all(connection).await?; + "#.to_string() +} - Ok(raw_weights) +fn query_builder<'a>( + username: &'a str, + enforce_limits: bool, + page_index: usize, + page_size: usize, + sort_ascending: bool, + select_fields: &'a str, + can_see_deleted: bool, +) -> QueryBuilder<'a, MySql> { + + // NB: Query cannot be statically checked by sqlx + let mut query_builder: QueryBuilder = QueryBuilder::new( + format!(r#" +SELECT + {select_fields} +FROM model_weights as mw +JOIN users as u + ON u.token = mw.creator_user_token + "# + )); + + if !can_see_deleted { + query_builder.push(" WHERE mw.user_deleted_at IS NULL AND mw.mod_deleted_at IS NULL "); } + + query_builder.push(" AND u.username = "); + query_builder.push_bind(username); + + + if sort_ascending { + query_builder.push(" ORDER BY mw.created_at ASC "); + } else { + query_builder.push(" ORDER BY mw.created_at DESC "); + } + + if enforce_limits { + let offset = page_index * page_size; + query_builder.push(format!(" LIMIT {page_size} OFFSET {offset} ")); + } + + query_builder } + async fn map_to_weights(dataset:Vec) -> Vec { let weights: Vec = dataset .into_iter() @@ -224,7 +261,6 @@ async fn map_to_weights(dataset:Vec) -> Vec) -> Vec for RawWeightJoinUser { + fn from_row(row: &MySqlRow) -> std::result::Result { + Ok(Self { + token: row.try_get("token")?, + weights_type: row.try_get("weights_type")?, + weights_category: row.try_get("weights_category")?, + title: row.try_get("title")?, + maybe_thumbnail_token: row.try_get("maybe_thumbnail_token")?, + description_markdown: row.try_get("description_markdown")?, + description_rendered_html: row.try_get("description_rendered_html")?, + creator_user_token: row.try_get("creator_user_token")?, + creator_ip_address: row.try_get("creator_ip_address")?, + creator_set_visibility: Visibility::try_from_mysql_row(row, "creator_set_visibility")?, + maybe_last_update_user_token: row.try_get("maybe_last_update_user_token")?, + original_download_url: row.try_get("original_download_url")?, + original_filename: row.try_get("original_filename")?, + file_size_bytes: row.try_get("file_size_bytes")?, + file_checksum_sha2: row.try_get("file_checksum_sha2")?, + public_bucket_hash: row.try_get("public_bucket_hash")?, + maybe_public_bucket_prefix: row.try_get("maybe_public_bucket_prefix")?, + maybe_public_bucket_extension: row.try_get("maybe_public_bucket_extension")?, + cached_user_ratings_total_count: row.try_get("cached_user_ratings_total_count")?, + cached_user_ratings_positive_count: row.try_get("cached_user_ratings_positive_count")?, + cached_user_ratings_negative_count: row.try_get("cached_user_ratings_negative_count")?, + maybe_cached_user_ratings_ratio: row.try_get("maybe_cached_user_ratings_ratio")?, + cached_user_ratings_last_updated_at: row.try_get("cached_user_ratings_last_updated_at")?, + version: row.try_get("version")?, + created_at: row.try_get("created_at")?, + updated_at: row.try_get("updated_at")?, + user_deleted_at: row.try_get("user_deleted_at")?, + mod_deleted_at: row.try_get("mod_deleted_at")?, + creator_username: row.try_get("creator_username")?, + creator_display_name: row.try_get("creator_display_name")?, + creator_email_gravatar_hash: row.try_get("creator_email_gravatar_hash")?, + }) + } +} \ No newline at end of file diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files_for_user.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files_for_user.rs index 2792561418..5206e4a6c5 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files_for_user.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/media_files/list_media_files_for_user.rs @@ -128,9 +128,7 @@ pub async fn list_media_files_for_user_handler( // TODO(bt,2023-12-04): Enforce real maximums and defaults let limit = query.page_size.unwrap_or(25); - let sort_ascending = query.sort_ascending.unwrap_or(false); - let page_size = query.page_size.unwrap_or_else(|| 25); let page_index = query.page_index.unwrap_or_else(|| 0); diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/list_weights_by_user.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/list_weights_by_user.rs index 54df007a1b..8cebb4a0a5 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/list_weights_by_user.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/list_weights_by_user.rs @@ -4,14 +4,16 @@ use std::sync::Arc; use actix_web::{HttpRequest, HttpResponse, web}; use actix_web::error::ResponseError; use actix_web::http::StatusCode; -use actix_web::web::Path; +use actix_web::web::{Path, Query}; use chrono::{DateTime, Utc}; use log::warn; -use utoipa::ToSchema; +use utoipa::{IntoParams, ToSchema}; +use enums::by_table::media_files::media_file_type::MediaFileType; use enums::common::visibility::Visibility; -use mysql_queries::queries::model_weights::list_weights_by_user::list_weights_by_creator_username; +use mysql_queries::queries::model_weights::list_weights_by_user::{list_weights_by_creator_username, ListWeightsForUserArgs}; use tokens::tokens::model_weights::ModelWeightToken; +use crate::http_server::common_responses::pagination_page::PaginationPage; use crate::http_server::common_responses::user_details_lite::UserDetailsLight; use crate::server_state::ServerState; @@ -45,9 +47,16 @@ pub struct Weight { #[derive(Serialize,ToSchema)] pub struct ListWeightsByUserSuccessResponse { pub success: bool, - pub weights: Vec, + pub results: Vec, + pub pagination: PaginationPage, } +#[derive(Deserialize, ToSchema, IntoParams)] +pub struct ListWeightsForUserQueryParams { + pub sort_ascending: Option, + pub page_size: Option, + pub page_index: Option, +} #[derive(Deserialize,ToSchema)] pub struct ListWeightsByUserPathInfo { username: String, @@ -84,11 +93,13 @@ impl ResponseError for ListWeightsByUserError { ), params( ("path" = ListWeightsByUserPathInfo, description = "Payload for Request"), + ListWeightsForUserQueryParams ) )] pub async fn list_weights_by_user_handler( http_request: HttpRequest, path: Path, + query: Query, server_state: web::Data> ) -> Result { @@ -112,25 +123,34 @@ pub async fn list_weights_by_user_handler( let username = path.username.as_ref(); let creator_user_token = user_session.user_token.clone(); let is_mod = user_session.can_ban_users; + let limit = query.page_size.unwrap_or(25); + let sort_ascending = query.sort_ascending.unwrap_or(false); + let page_size = query.page_size.unwrap_or_else(|| 25); + let page_index = query.page_index.unwrap_or_else(|| 0); let query_results = list_weights_by_creator_username( - &server_state.mysql_pool, - &username, - is_mod, + ListWeightsForUserArgs{ + creator_username: username, + page_size, + page_index, + can_see_deleted: is_mod, + sort_ascending, + mysql_pool: &server_state.mysql_pool, + } ).await.map_err(|e| { warn!("Error querying for weights: {:?}", e); ListWeightsByUserError::ServerError }); - let weights = match query_results { - Ok(weights) => weights, + let results_page = match query_results { + Ok(results) => results, Err(e) => { warn!("Error querying for weights: {:?}", e); return Err(ListWeightsByUserError::ServerError); } }; - let weights:Vec = weights.into_iter().map(|weight| { + let weights:Vec = results_page.records.into_iter().map(|weight| { Weight { weight_token: weight.token, title: weight.title, @@ -172,7 +192,11 @@ pub async fn list_weights_by_user_handler( let response: ListWeightsByUserSuccessResponse = ListWeightsByUserSuccessResponse { success: true, - weights: final_weights, + results: final_weights, + pagination: PaginationPage { + current: results_page.current_page, + total_page_count: results_page.total_page_count, + }, }; From 71360879f3bf869b5721b29b23281fa02288a2f8 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Thu, 21 Dec 2023 18:43:18 -0500 Subject: [PATCH 119/124] cleanup --- .../{ => list}/list_weights_by_tokens.rs | 0 .../{ => list}/list_weights_by_user.rs | 3 +- .../{ => list}/list_weights_query_builder.rs | 19 ++++++----- .../src/queries/model_weights/list/mod.rs | 5 ++- .../src/queries/model_weights/mod.rs | 5 +-- .../src/queries/model_weights/tests.rs | 6 ++-- .../weights/list_available_weights.rs | 32 ++++++++----------- .../weights/list_featured_weights.rs | 2 +- .../endpoints/weights/list_weights_by_user.rs | 5 ++- execute_all_tests_and_lints.sh | 1 + 10 files changed, 36 insertions(+), 42 deletions(-) rename crates/lib/mysql_queries/src/queries/model_weights/{ => list}/list_weights_by_tokens.rs (100%) rename crates/lib/mysql_queries/src/queries/model_weights/{ => list}/list_weights_by_user.rs (99%) rename crates/lib/mysql_queries/src/queries/model_weights/{ => list}/list_weights_query_builder.rs (99%) diff --git a/crates/lib/mysql_queries/src/queries/model_weights/list_weights_by_tokens.rs b/crates/lib/mysql_queries/src/queries/model_weights/list/list_weights_by_tokens.rs similarity index 100% rename from crates/lib/mysql_queries/src/queries/model_weights/list_weights_by_tokens.rs rename to crates/lib/mysql_queries/src/queries/model_weights/list/list_weights_by_tokens.rs diff --git a/crates/lib/mysql_queries/src/queries/model_weights/list_weights_by_user.rs b/crates/lib/mysql_queries/src/queries/model_weights/list/list_weights_by_user.rs similarity index 99% rename from crates/lib/mysql_queries/src/queries/model_weights/list_weights_by_user.rs rename to crates/lib/mysql_queries/src/queries/model_weights/list/list_weights_by_user.rs index 00ec55a5a5..014548007a 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/list_weights_by_user.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/list/list_weights_by_user.rs @@ -1,5 +1,5 @@ use chrono::{DateTime, Utc}; -use sqlx::{Acquire, FromRow, MySql, MySqlConnection, MySqlPool, QueryBuilder, Row}; +use sqlx::{FromRow, MySql, MySqlPool, QueryBuilder, Row}; use sqlx::mysql::MySqlRow; use enums::by_table::model_weights::{ @@ -12,7 +12,6 @@ use errors::AnyhowResult; use tokens::tokens::model_weights::ModelWeightToken; use tokens::tokens::users::UserToken; - pub struct WeightsForUserListPage { pub records: Vec, diff --git a/crates/lib/mysql_queries/src/queries/model_weights/list_weights_query_builder.rs b/crates/lib/mysql_queries/src/queries/model_weights/list/list_weights_query_builder.rs similarity index 99% rename from crates/lib/mysql_queries/src/queries/model_weights/list_weights_query_builder.rs rename to crates/lib/mysql_queries/src/queries/model_weights/list/list_weights_query_builder.rs index 078ed937ed..270501e94d 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/list_weights_query_builder.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/list/list_weights_query_builder.rs @@ -2,20 +2,18 @@ #![forbid(unused_mut)] #![forbid(unused_variables)] -use chrono::{ DateTime, Utc }; - +use chrono::{DateTime, Utc}; use sqlx::MySqlPool; use config::shared_constants::DEFAULT_MYSQL_QUERY_RESULT_PAGE_SIZE; +use enums::by_table::model_weights::{ + weights_category::WeightsCategory, + weights_types::WeightsType, +}; use enums::common::visibility::Visibility; use errors::AnyhowResult; -use tokens::tokens::users::UserToken; use tokens::tokens::model_weights::ModelWeightToken; - -use enums::by_table::model_weights::{ - weights_types::WeightsType, - weights_category::WeightsCategory, -}; +use tokens::tokens::users::UserToken; #[derive(Serialize)] pub struct WeightsPage { @@ -466,12 +464,13 @@ struct RawWeightJoinUser { #[cfg(test)] mod tests { - use crate::queries::model_weights::list_weights_query_builder::ListWeightsQueryBuilder; use enums::by_table::model_weights::{ - weights_types::WeightsType, weights_category::WeightsCategory, + weights_types::WeightsType, }; + use crate::queries::model_weights::list::list_weights_query_builder::ListWeightsQueryBuilder; + #[test] fn predicates_without_scoping() { let query_builder = ListWeightsQueryBuilder::new(); diff --git a/crates/lib/mysql_queries/src/queries/model_weights/list/mod.rs b/crates/lib/mysql_queries/src/queries/model_weights/list/mod.rs index 597399a9c0..d55564a1a3 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/list/mod.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/list/mod.rs @@ -1 +1,4 @@ -pub mod list_model_weights_for_voice_conversion; \ No newline at end of file +pub mod list_model_weights_for_voice_conversion; +pub mod list_weights_by_tokens; +pub mod list_weights_by_user; +pub mod list_weights_query_builder; \ No newline at end of file diff --git a/crates/lib/mysql_queries/src/queries/model_weights/mod.rs b/crates/lib/mysql_queries/src/queries/model_weights/mod.rs index 3be8bbd553..798b1df3a0 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/mod.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/mod.rs @@ -5,10 +5,7 @@ pub mod edit; pub mod get_weight; pub mod inference; pub mod list; -pub mod list_weights_by_tokens; -pub mod list_weights_by_user; -pub mod list_weights_query_builder; pub mod migration; pub mod model_weight_info_lite; pub mod tests; -pub mod update_weight; +pub mod update_weight; \ No newline at end of file diff --git a/crates/lib/mysql_queries/src/queries/model_weights/tests.rs b/crates/lib/mysql_queries/src/queries/model_weights/tests.rs index aae8a097fb..bc88050941 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/tests.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/tests.rs @@ -3,8 +3,8 @@ mod tests { use anyhow::Ok; use rand::Rng; use serial_test::serial; - use sqlx::MySqlPool; use sqlx::mysql::MySqlPoolOptions; + use sqlx::MySqlPool; use tokio; use config::shared_constants::DEFAULT_MYSQL_CONNECTION_STRING; @@ -26,8 +26,8 @@ mod tests { undelete_weights_as_user, }; use crate::queries::model_weights::get_weight::get_weight_by_token; - use crate::queries::model_weights::list_weights_by_user::list_weights_by_creator_username; - use crate::queries::model_weights::list_weights_query_builder::ListWeightsQueryBuilder; + use crate::queries::model_weights::list::list_weights_by_user::list_weights_by_creator_username; + use crate::queries::model_weights::list::list_weights_query_builder::ListWeightsQueryBuilder; use crate::queries::users::user::get_user_token_by_username::get_user_token_by_username; async fn setup() -> sqlx::Pool { diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/list_available_weights.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/list_available_weights.rs index f191e40410..31ca53bb86 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/list_available_weights.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/list_available_weights.rs @@ -1,27 +1,23 @@ use std::sync::Arc; -use actix_web::web::Query; -use actix_web::{ HttpRequest, HttpResponse, web }; + +use actix_web::{HttpRequest, HttpResponse, web}; use actix_web::error::ResponseError; use actix_web::http::StatusCode; -use chrono::{ DateTime, Utc }; -use log::{ info, warn }; +use chrono::{DateTime, Utc}; +use log::{info, warn}; use rand::Rng; -use enums::common::visibility::Visibility; -use mysql_queries::queries::model_weights::list_weights_query_builder::ListWeightsQueryBuilder; - -use enums::by_table::model_weights::{ - weights_types::WeightsType, - weights_category::WeightsCategory, -}; - -use tokens::tokens::users::UserToken; -use tokens::tokens::model_weights::ModelWeightToken; - -use crate::http_server::common_responses::user_details_lite::{UserDetailsLight,DefaultAvatarInfo}; -use crate::server_state::ServerState; - use utoipa::ToSchema; +use enums::by_table::model_weights::{ + weights_category::WeightsCategory, + weights_types::WeightsType, +}; +use enums::common::visibility::Visibility; +use mysql_queries::queries::model_weights::list::list_weights_query_builder::ListWeightsQueryBuilder; +use tokens::tokens::model_weights::ModelWeightToken; +use tokens::tokens::users::UserToken; + +use crate::server_state::ServerState; #[derive(Deserialize,ToSchema)] pub struct ListAvailableWeightsQuery { diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/list_featured_weights.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/list_featured_weights.rs index 87d75eed0f..e761e3a448 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/list_featured_weights.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/list_featured_weights.rs @@ -12,7 +12,7 @@ use enums::by_table::model_weights::{ weights_category::WeightsCategory, weights_types::WeightsType, }; -use mysql_queries::queries::model_weights::list_weights_by_tokens::list_weights_by_tokens; +use mysql_queries::queries::model_weights::list::list_weights_by_tokens::list_weights_by_tokens; use tokens::tokens::model_weights::ModelWeightToken; use crate::http_server::common_responses::user_details_lite::UserDetailsLight; diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/list_weights_by_user.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/list_weights_by_user.rs index 8cebb4a0a5..e93c50d50e 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/list_weights_by_user.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/list_weights_by_user.rs @@ -8,13 +8,12 @@ use actix_web::web::{Path, Query}; use chrono::{DateTime, Utc}; use log::warn; use utoipa::{IntoParams, ToSchema}; -use enums::by_table::media_files::media_file_type::MediaFileType; use enums::common::visibility::Visibility; -use mysql_queries::queries::model_weights::list_weights_by_user::{list_weights_by_creator_username, ListWeightsForUserArgs}; +use mysql_queries::queries::model_weights::list::list_weights_by_user::{list_weights_by_creator_username, ListWeightsForUserArgs}; use tokens::tokens::model_weights::ModelWeightToken; -use crate::http_server::common_responses::pagination_page::PaginationPage; +use crate::http_server::common_responses::pagination_page::PaginationPage; use crate::http_server::common_responses::user_details_lite::UserDetailsLight; use crate::server_state::ServerState; diff --git a/execute_all_tests_and_lints.sh b/execute_all_tests_and_lints.sh index 3df28c0824..8faf115296 100755 --- a/execute_all_tests_and_lints.sh +++ b/execute_all_tests_and_lints.sh @@ -4,6 +4,7 @@ set -euxo pipefail echo 'Run cargo check...' +#RUSTFLAGS=-Awarnings cargo check cargo check echo 'Run lints...' From 43da5c91ad6702f5e4d1e456dbf41746bfa16953 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Thu, 21 Dec 2023 18:47:28 -0500 Subject: [PATCH 120/124] fix compile error --- .../src/queries/model_weights/tests.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/crates/lib/mysql_queries/src/queries/model_weights/tests.rs b/crates/lib/mysql_queries/src/queries/model_weights/tests.rs index bc88050941..c964160692 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/tests.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/tests.rs @@ -26,7 +26,7 @@ mod tests { undelete_weights_as_user, }; use crate::queries::model_weights::get_weight::get_weight_by_token; - use crate::queries::model_weights::list::list_weights_by_user::list_weights_by_creator_username; + use crate::queries::model_weights::list::list_weights_by_user::{list_weights_by_creator_username, ListWeightsForUserArgs}; use crate::queries::model_weights::list::list_weights_query_builder::ListWeightsQueryBuilder; use crate::queries::users::user::get_user_token_by_username::get_user_token_by_username; @@ -290,11 +290,14 @@ mod tests { &creator_username ).await?; - let weights_by_username = list_weights_by_creator_username( - &pool, - &creator_username, - can_see_deleted - ).await?; + let weights_by_username = list_weights_by_creator_username(ListWeightsForUserArgs { + creator_username: &creator_username, + page_size: 0, + page_index: 0, + sort_ascending: false, + can_see_deleted, + mysql_pool: &pool, + }).await?; for weight in weights_by_username.iter() { // print weight println!("weight: {:?}", weight.creator_username); From 7897ef730e24c1ee069be4db56409ddac8f23ed9 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Thu, 21 Dec 2023 19:04:56 -0500 Subject: [PATCH 121/124] refactor, fix tests --- crates/cli/dev-database-seed/src/seeding/model_weights.rs | 2 +- .../dev-database-seed/src/seeding/seed_model_weights.rs | 2 +- .../queries/model_weights/{ => create}/create_weight.rs | 0 .../mysql_queries/src/queries/model_weights/create/mod.rs | 3 ++- .../mysql_queries/src/queries/model_weights/edit/mod.rs | 3 ++- .../src/queries/model_weights/{ => edit}/update_weight.rs | 0 crates/lib/mysql_queries/src/queries/model_weights/mod.rs | 2 -- .../lib/mysql_queries/src/queries/model_weights/tests.rs | 8 ++++---- .../src/http_server/endpoints/weights/update_weight.rs | 2 +- 9 files changed, 11 insertions(+), 11 deletions(-) rename crates/lib/mysql_queries/src/queries/model_weights/{ => create}/create_weight.rs (100%) rename crates/lib/mysql_queries/src/queries/model_weights/{ => edit}/update_weight.rs (100%) diff --git a/crates/cli/dev-database-seed/src/seeding/model_weights.rs b/crates/cli/dev-database-seed/src/seeding/model_weights.rs index 96233496d5..f5f16cfb81 100644 --- a/crates/cli/dev-database-seed/src/seeding/model_weights.rs +++ b/crates/cli/dev-database-seed/src/seeding/model_weights.rs @@ -9,7 +9,7 @@ use enums::by_table::model_weights::{ }; use enums::common::visibility::Visibility; use errors::{anyhow, AnyhowResult}; -use mysql_queries::queries::model_weights::create_weight::{create_weight, CreateModelWeightsArgs}; +use mysql_queries::queries::model_weights::create::create_weight::{create_weight, CreateModelWeightsArgs}; use mysql_queries::queries::users::user::get_user_token_by_username::get_user_token_by_username; use tokens::tokens::model_weights::ModelWeightToken; use tokens::tokens::users::UserToken; diff --git a/crates/cli/dev-database-seed/src/seeding/seed_model_weights.rs b/crates/cli/dev-database-seed/src/seeding/seed_model_weights.rs index 5f0bb838bb..24b0a5efa8 100644 --- a/crates/cli/dev-database-seed/src/seeding/seed_model_weights.rs +++ b/crates/cli/dev-database-seed/src/seeding/seed_model_weights.rs @@ -15,7 +15,7 @@ use filesys::file_size::file_size; use filesys::path_to_string::path_to_string; use hashing::sha256::sha256_hash_file::sha256_hash_file; use mimetypes::mimetype_for_bytes::get_mimetype_for_bytes; -use mysql_queries::queries::model_weights::create_weight::{ +use mysql_queries::queries::model_weights::create::create_weight::{ create_weight, CreateModelWeightsArgs, }; diff --git a/crates/lib/mysql_queries/src/queries/model_weights/create_weight.rs b/crates/lib/mysql_queries/src/queries/model_weights/create/create_weight.rs similarity index 100% rename from crates/lib/mysql_queries/src/queries/model_weights/create_weight.rs rename to crates/lib/mysql_queries/src/queries/model_weights/create/create_weight.rs diff --git a/crates/lib/mysql_queries/src/queries/model_weights/create/mod.rs b/crates/lib/mysql_queries/src/queries/model_weights/create/mod.rs index 2b876c4c48..5ed7f83cf7 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/create/mod.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/create/mod.rs @@ -1 +1,2 @@ -pub mod create_model_weight_from_voice_conversion_download_job; \ No newline at end of file +pub mod create_model_weight_from_voice_conversion_download_job; +pub mod create_weight; diff --git a/crates/lib/mysql_queries/src/queries/model_weights/edit/mod.rs b/crates/lib/mysql_queries/src/queries/model_weights/edit/mod.rs index d2628b7b1e..bbac2db88a 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/edit/mod.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/edit/mod.rs @@ -1 +1,2 @@ -pub mod set_model_weight_avatar; \ No newline at end of file +pub mod set_model_weight_avatar; +pub mod update_weight; diff --git a/crates/lib/mysql_queries/src/queries/model_weights/update_weight.rs b/crates/lib/mysql_queries/src/queries/model_weights/edit/update_weight.rs similarity index 100% rename from crates/lib/mysql_queries/src/queries/model_weights/update_weight.rs rename to crates/lib/mysql_queries/src/queries/model_weights/edit/update_weight.rs diff --git a/crates/lib/mysql_queries/src/queries/model_weights/mod.rs b/crates/lib/mysql_queries/src/queries/model_weights/mod.rs index 798b1df3a0..8170d5ddfd 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/mod.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/mod.rs @@ -1,5 +1,4 @@ pub mod create; -pub mod create_weight; pub mod delete_weights; pub mod edit; pub mod get_weight; @@ -8,4 +7,3 @@ pub mod list; pub mod migration; pub mod model_weight_info_lite; pub mod tests; -pub mod update_weight; \ No newline at end of file diff --git a/crates/lib/mysql_queries/src/queries/model_weights/tests.rs b/crates/lib/mysql_queries/src/queries/model_weights/tests.rs index c964160692..9b92e9440a 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/tests.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/tests.rs @@ -17,8 +17,8 @@ mod tests { use enums::common::visibility::Visibility; use tokens::tokens::{model_weights::ModelWeightToken, users::UserToken}; - use crate::queries::model_weights::create_weight::create_weight; - use crate::queries::model_weights::create_weight::CreateModelWeightsArgs; + use crate::queries::model_weights::create::create_weight::create_weight; + use crate::queries::model_weights::create::create_weight::CreateModelWeightsArgs; use crate::queries::model_weights::delete_weights::{ delete_weights_as_mod, delete_weights_as_user, @@ -298,11 +298,11 @@ mod tests { can_see_deleted, mysql_pool: &pool, }).await?; - for weight in weights_by_username.iter() { + for weight in weights_by_username.records.iter() { // print weight println!("weight: {:?}", weight.creator_username); } - assert_eq!(weights_by_username.len(), 5); + assert_eq!(weights_by_username.records.len(), 5); Ok(()) } diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/update_weight.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/update_weight.rs index 8f69470054..9f69aefcdc 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/update_weight.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/update_weight.rs @@ -11,7 +11,7 @@ use enums::common::visibility::Visibility; use http_server_common::response::response_success_helpers::simple_json_success; use http_server_common::response::serialize_as_json_error::serialize_as_json_error; use mysql_queries::queries::model_weights::get_weight::get_weight_by_token; -use mysql_queries::queries::model_weights::update_weight::{ update_weights, UpdateWeightArgs }; +use mysql_queries::queries::model_weights::edit::update_weight::{ update_weights, UpdateWeightArgs }; use tokens::tokens::model_weights::ModelWeightToken; use crate::server_state::ServerState; From 268346f6623e999585c4b976afa41720dd81bdcc Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Thu, 21 Dec 2023 19:40:33 -0500 Subject: [PATCH 122/124] delete more easily --- .../weights/set_model_weight_avatar.rs | 51 +++++++++++-------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/set_model_weight_avatar.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/set_model_weight_avatar.rs index effe9f289f..0bd3a3c27c 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/set_model_weight_avatar.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/set_model_weight_avatar.rs @@ -124,31 +124,38 @@ pub async fn set_model_weight_avatar_handler( let mut maybe_set_media_file_token = None; - if let Some(media_file_token) = &request.avatar_media_file_token { - let media_file_lookup_result = get_media_file( - &media_file_token, - false, - &server_state.mysql_pool, - ).await; + let delete_avatar = request.avatar_media_file_token + .as_ref() + .map(|token| token.as_str().trim().is_empty()) + .unwrap_or(true); - let media_file = match media_file_lookup_result { - Ok(Some(model_weight)) => model_weight, - Ok(None) => { - warn!("Media file not found: {:?}", media_file_token); - return Err(SetModelWeightAvatarError::NotFound); - }, - Err(err) => { - warn!("Error looking up model_weights : {:?}", err); - return Err(SetModelWeightAvatarError::ServerError); + if !delete_avatar { + if let Some(media_file_token) = &request.avatar_media_file_token { + let media_file_lookup_result = get_media_file( + &media_file_token, + false, + &server_state.mysql_pool, + ).await; + + let media_file = match media_file_lookup_result { + Ok(Some(model_weight)) => model_weight, + Ok(None) => { + warn!("Media file not found: {:?}", media_file_token); + return Err(SetModelWeightAvatarError::NotFound); + }, + Err(err) => { + warn!("Error looking up model_weights : {:?}", err); + return Err(SetModelWeightAvatarError::ServerError); + } + }; + + if media_file.creator_set_visibility != Visibility::Public + || media_file.media_type != MediaFileType::Image { + return Err(SetModelWeightAvatarError::BadInput("Invalid media file token.".to_string())); } - }; - if media_file.creator_set_visibility != Visibility::Public - || media_file.media_type != MediaFileType::Image { - return Err(SetModelWeightAvatarError::BadInput("Invalid media file token.".to_string())); + maybe_set_media_file_token = Some(media_file.token); } - - maybe_set_media_file_token = Some(media_file.token); } // TODO(bt,2023-12-21): DB needs a column, or we need an ip audit log @@ -157,7 +164,7 @@ pub async fn set_model_weight_avatar_handler( let query_result = set_model_weight_avatar(UpdateArgs { model_weight_token: &path.token, maybe_avatar_media_file_token: maybe_set_media_file_token.as_ref(), - mysql_pool: &server_state.mysql_pool + mysql_pool: &server_state.mysql_pool, }).await; match query_result { From 15c218286f467c35f61ccb56ac24cc0c587b7bf5 Mon Sep 17 00:00:00 2001 From: Michael Chung Date: Thu, 21 Dec 2023 19:51:32 -0500 Subject: [PATCH 123/124] Bucket Orchestration work complete. --- .../bucket_orchestration.rs | 2 + .../src/remote_file_manager/file_directory.rs | 2 +- .../remote_cloud_bucket_details.rs | 5 +- .../remote_cloud_file_manager.rs | 46 +++++++++---------- .../bucket_orchestration_mock.rs | 2 - 5 files changed, 27 insertions(+), 30 deletions(-) diff --git a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/bucket_orchestration.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/bucket_orchestration.rs index 3ecc452e99..6f0240e631 100644 --- a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/bucket_orchestration.rs +++ b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/bucket_orchestration.rs @@ -5,6 +5,7 @@ use async_trait::async_trait; use errors::AnyhowResult; use crate::bucket_client::BucketClient; +use crate::remote_file_manager::file_meta_data::FileMetaData; #[async_trait] pub trait BucketOrchestrationCore { @@ -19,6 +20,7 @@ pub trait BucketOrchestrationCore { bytes: &[u8], content_type: &str, is_public: bool) -> AnyhowResult<()>; + } diff --git a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/file_directory.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/file_directory.rs index 70274a9f9c..807dffdca5 100644 --- a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/file_directory.rs +++ b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/file_directory.rs @@ -48,7 +48,7 @@ pub struct FileBucketDirectory { // gets you name of the file with suffix and prefix and entropy in the centre let file_name = format!("{}_{}.{}", file_descriptor.get_prefix(), entropy, file_descriptor.get_suffix()); // note: no longer optional because it's easy to know what it would be in the db explicit is better than implcit. - + // This is the full path you upload to. let full_remote_cloud_file_path = format!("{}/{}", remote_cloud_base_directory , file_name); Self { diff --git a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_bucket_details.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_bucket_details.rs index 28cbe1c993..5a44e23119 100644 --- a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_bucket_details.rs +++ b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_bucket_details.rs @@ -50,8 +50,9 @@ impl RemoteCloudBucketDetails { #[cfg(test)] mod tests { use super::*; - #[test] - pub fn test() {} + pub fn test() { + + } } \ No newline at end of file diff --git a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_file_manager.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_file_manager.rs index 3d2dff3fdf..6240e07c27 100644 --- a/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_file_manager.rs +++ b/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_file_manager.rs @@ -13,11 +13,8 @@ use filesys::file_read_bytes::file_read_bytes; use filesys::file_size::file_size; use hashing::sha256::sha256_hash_file::sha256_hash_file; - use mimetypes::mimetype_for_bytes::get_mimetype_for_bytes; - - use crate::remote_file_manager::bucket_orchestration::{BucketOrchestrationCore}; struct RemoteCloudFileClient { @@ -55,7 +52,7 @@ impl RemoteCloudFileClient { file_descriptor ); - println!("Uploading media file to bucket path: {:?}",directory.get_remote_cloud_base_directory()); + println!("Uploading media file to bucket path: {:?}",directory.get_full_remote_cloud_file_path()); self.bucket_orchestration_client.upload_file_with_content_type_process( &directory.get_remote_cloud_base_directory(), @@ -85,17 +82,15 @@ impl RemoteCloudFileClient { #[cfg(test)] mod tests { + use async_trait::async_trait; use env_logger; use errors::AnyhowResult; use crate::remote_file_manager::bucket_orchestration::BucketOrchestrationCore; use crate::remote_file_manager::weights_descriptor::{WeightsLoRADescriptor, WeightsSD15Descriptor, WeightsSDXLDescriptor}; - use super::bucket_orchestration; + struct BucketOrchestrationMock {} - struct BucketOrchestrationMock { - - } - #[async-trait] + #[async_trait] impl BucketOrchestrationCore for BucketOrchestrationMock { async fn download_file_to_disk( &self, @@ -107,16 +102,26 @@ mod tests { println!("{}",object_path); println!("{}",filesystem_path); println!("{}",is_public); + println!("Download Done Downloading"); + + assert_eq!(String::from("/weights/1/2/123/loRA_123.safetensors"),object_path); + assert_eq!(String::from("./file_path_here"),filesystem_path); + assert_eq!(is_public,true); Ok(()) } + async fn upload_file_with_content_type_process(&self, object_name: &str, bytes: &[u8], content_type: &str, is_public: bool) -> AnyhowResult<()> { println!("Upload File to Disk"); println!("{}",object_name); - println!("{}",content_type); + assert_eq!(object_name,String::from("/weights/2/y/q/m/2/2yqm2f1bamh88seyd690h9v24apgezhr/loRA_2yqm2f1bamh88seyd690h9v24apgezhr.safetensors")); + println!("ContentType:{}",content_type); println!("{}",is_public); + assert_eq!(is_public,true); + + println!("Is Done Uploading"); Ok(()) } } @@ -130,7 +135,7 @@ mod tests { assert_eq!(file_descriptor.get_prefix(), "loRA"); assert_eq!(file_descriptor.get_suffix(), "safetensors"); - assert_eq!(file_descriptor.is_public(), false); + assert_eq!(file_descriptor.is_public(), true); } #[tokio::test] @@ -141,11 +146,8 @@ mod tests { let file_path:&str= "./file_path_here"; - // let seed_tool_data_root = get_seed_tool_data_root(); - // let file_path = seed_tool_data_root.join(file_path); - let file_path = file_path.to_str().unwrap(); let remote_cloud_file_manager = RemoteCloudFileClient { - bucket_orchestration_client: Box::new(BucketOrchestrationCore {}) + bucket_orchestration_client: Box::new(BucketOrchestrationMock {}) }; println!("begin upload from file_path: {:?}", file_path); @@ -154,7 +156,7 @@ mod tests { prefix: String::from("loRA"), suffix: String::from("safetensors") }; - let result = remote_cloud_file_manager.download_file(details,file_path).await; + let result = remote_cloud_file_manager.download_file(details,file_path.to_string()).await; match result { Ok(file_meta_data) => { @@ -171,14 +173,11 @@ mod tests { use super::*; env_logger::init(); + // Replace with a test file. + let weight_path:&str= "/home/tensor/code/storyteller/storyteller-rust/crates/lib/api_clients/cloud_storage/src/remote_file_manager/remote_cloud_file_manager.rs"; - let weight_path:&str= "models/imagegen/loRA/nijiMecha.safetensors"; - - // let seed_tool_data_root = get_seed_tool_data_root(); - // let weight_path = seed_tool_data_root.join(weight_path); - let weight_path = weight_path.to_str().unwrap(); let remote_cloud_file_manager = RemoteCloudFileClient { - bucket_orchestration_client: Box::new(BucketOrchestrationCore {}) + bucket_orchestration_client: Box::new(BucketOrchestrationMock {}) }; println!("begin upload from weight_path: {:?}", weight_path); @@ -194,7 +193,4 @@ mod tests { } } } - - - } \ No newline at end of file diff --git a/crates/lib/api_clients/cloud_storage/src/remote_file_manager_mock/bucket_orchestration_mock.rs b/crates/lib/api_clients/cloud_storage/src/remote_file_manager_mock/bucket_orchestration_mock.rs index 139597f9cb..e69de29bb2 100644 --- a/crates/lib/api_clients/cloud_storage/src/remote_file_manager_mock/bucket_orchestration_mock.rs +++ b/crates/lib/api_clients/cloud_storage/src/remote_file_manager_mock/bucket_orchestration_mock.rs @@ -1,2 +0,0 @@ - - From 08f59a19893a4bad26bfd5e7bbd93ae77f685dc7 Mon Sep 17 00:00:00 2001 From: ArEnSc <6252325+ArEnSc@users.noreply.github.com> Date: Thu, 21 Dec 2023 19:53:07 -0500 Subject: [PATCH 124/124] Update .env --- .env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env b/.env index c41492d472..a39f1b1d8d 100644 --- a/.env +++ b/.env @@ -76,4 +76,4 @@ TTS_HIFIGAN_SUPERRES_VOCODER_MODEL_FILENAME=hifigan_superres_twilight_33000.pt # Development key. Permissible to check in. NEWRELIC_API_KEY=c402be1c4c4216ec83d0cfc0851520cfFFFFNRAL -STORYTELLER_ROOT="/home/tensor/code/storyteller/" # Put this in .env-secrets so that not everyone gets this setting. +#STORYTELLER_ROOT="/home/tensor/code/storyteller/" # Put this in .env-secrets so that not everyone gets this setting.