From ac4a7f4612e886010dfb24915e30036a43cd5bd7 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Sun, 29 Sep 2024 01:51:12 -0400 Subject: [PATCH] update model language --- .../model_weights/edit/update_weight.rs | 21 ++++++++--- .../configs/supported_languages_for_models.rs | 29 +++++++++++++-- .../weights/update/update_weight_handler.rs | 37 +++++++++++++++++++ 3 files changed, 79 insertions(+), 8 deletions(-) diff --git a/crates/lib/mysql_queries/src/queries/model_weights/edit/update_weight.rs b/crates/lib/mysql_queries/src/queries/model_weights/edit/update_weight.rs index 212d7c6952..cc6657d598 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/edit/update_weight.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/edit/update_weight.rs @@ -14,6 +14,8 @@ pub struct UpdateWeightArgs<'a, 't> { pub maybe_description_markdown: Option<&'a str>, pub maybe_description_rendered_html: Option<&'a str>, pub creator_set_visibility: Option<&'a Visibility>, + pub ietf_language_tag: Option<&'a str>, + pub ietf_primary_language_subtag: Option<&'a str>, pub transactor: Transactor<'a, 't>, } @@ -42,19 +44,19 @@ SET let mut separated = query_builder.separated(", "); if let Some(title) = args.title { - separated.push("title = "); + separated.push(" title = "); separated.push_bind_unseparated(title); } if let Some(maybe_description_markdown) = args.maybe_description_markdown { - separated.push("maybe_description_markdown = "); + separated.push(" maybe_description_markdown = "); separated.push_bind_unseparated(maybe_description_markdown); } if let Some(maybe_description_rendered_html) = args.maybe_description_rendered_html { - separated.push("maybe_description_rendered_html = "); + separated.push(" maybe_description_rendered_html = "); separated.push_bind_unseparated(maybe_description_rendered_html); } if let Some(creator_set_visibility) = args.creator_set_visibility { - separated.push("creator_set_visibility = "); + separated.push(" creator_set_visibility = "); separated.push_bind_unseparated(creator_set_visibility.to_str()); } if let Some(cover_image_option) = args.cover_image { @@ -63,11 +65,20 @@ SET separated.push(" maybe_cover_image_media_file_token = NULL "); } CoverImageOption::SetCoverImage(media_file_token) => { - separated.push("maybe_cover_image_media_file_token = "); + separated.push(" maybe_cover_image_media_file_token = "); separated.push_bind_unseparated(media_file_token.as_str()); } } } + if let Some(ietf_language_tag) = args.ietf_language_tag { + if let Some(ietf_primary_language_subtag) = args.ietf_primary_language_subtag { + separated.push(" maybe_ietf_language_tag = "); + separated.push_bind_unseparated(ietf_language_tag); + + separated.push(" maybe_ietf_primary_language_subtag = "); + separated.push_bind_unseparated(ietf_primary_language_subtag); + } + } separated.push("version = version + 1"); diff --git a/crates/service/web/storyteller_web/src/configs/supported_languages_for_models.rs b/crates/service/web/storyteller_web/src/configs/supported_languages_for_models.rs index 29469158f3..1529c6c9d9 100644 --- a/crates/service/web/storyteller_web/src/configs/supported_languages_for_models.rs +++ b/crates/service/web/storyteller_web/src/configs/supported_languages_for_models.rs @@ -1,6 +1,6 @@ -use std::collections::{HashMap, HashSet}; - +use language_tags::LanguageTag; use once_cell::sync::Lazy; +use std::collections::{HashMap, HashSet}; /// These are language tags we try to support. static SUPPORTED_LANGUAGES_FOR_MODELS : Lazy> = Lazy::new(|| { @@ -39,6 +39,10 @@ static SUPPORTED_LANGUAGES_FOR_MODELS : Lazy> = Lazy::new(|| { "de-LI", // German (Liechtenstein) "de-LU", // German (Luxembourg) + // Hindi + "hi", + "hi-IN", // Hindi (India) + // Italian "it", "it-CH", // https://en.wikipedia.org/wiki/Swiss_Italian @@ -112,9 +116,16 @@ pub fn is_valid_language_for_models(language_tag: &str) -> bool { SUPPORTED_LANGUAGES_FOR_MODELS.contains(language_tag) } +/// Parse a language tag like "en-US" to "en". +pub fn get_primary_language_subtag(language_tag: &str) -> Option { + LanguageTag::parse(language_tag) + .map(|language_tag| language_tag.primary_language().to_string()) + .ok() +} + #[cfg(test)] mod tests { - use crate::configs::supported_languages_for_models::{get_canonicalized_language_tag_for_model, is_valid_language_for_models}; + use crate::configs::supported_languages_for_models::{get_canonicalized_language_tag_for_model, get_primary_language_subtag, is_valid_language_for_models}; #[test] fn get_canonical_language_for_model_success() { @@ -148,5 +159,17 @@ mod tests { assert!(!is_valid_language_for_models("foo")); assert!(!is_valid_language_for_models("en-FOO")); } + + #[test] + fn test_primary_language_subtag() { + assert_eq!(Some("en".to_string()), get_primary_language_subtag("en-US")); + assert_eq!(Some("es".to_string()), get_primary_language_subtag("es-419")); + assert_eq!(Some("it".to_string()), get_primary_language_subtag("it-CH")); + assert_eq!(Some("ja".to_string()), get_primary_language_subtag("ja-JP")); + assert_eq!(Some("zh".to_string()), get_primary_language_subtag("zh-CN")); + assert_eq!(Some("zh".to_string()), get_primary_language_subtag("zh-HK")); + assert_eq!(Some("tr".to_string()), get_primary_language_subtag("tr-TR")); + assert_eq!(Some("ar".to_string()), get_primary_language_subtag("ar-EG")); + } } diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/update/update_weight_handler.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/update/update_weight_handler.rs index 6a19f729c4..5370721ac2 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/weights/update/update_weight_handler.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/weights/update/update_weight_handler.rs @@ -10,6 +10,7 @@ use sqlx::MySqlPool; use utoipa::ToSchema; use enums::by_table::media_files::media_file_type::MediaFileType; +use enums::by_table::model_weights::weights_types::WeightsType; 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; @@ -21,6 +22,7 @@ use mysql_queries::utils::transactor::Transactor; use tokens::tokens::media_files::MediaFileToken; use tokens::tokens::model_weights::ModelWeightToken; use user_input_common::check_for_slurs::contains_slurs; +use crate::configs::supported_languages_for_models::{get_canonicalized_language_tag_for_model, get_primary_language_subtag}; use crate::http_server::web_utils::user_session::require_user_session::RequireUserSessionError; use crate::http_server::web_utils::user_session::require_user_session_using_connection::require_user_session_using_connection; use crate::state::server_state::ServerState; @@ -36,6 +38,13 @@ pub struct UpdateWeightRequest { /// The media file token of the *image* media file. /// Set to *empty string* to clear the cover image. pub cover_image_media_file_token: Option, + + /// An IETF BCP47 language tag, e.g.: "en", "en-US", + /// "es-419", "ja-JP", etc. + /// This is only applicable to TTS and Voice Conversion models. + /// If set for other model types, the endpoint will 400. + pub language_tag: Option, + pub visibility: Option, } @@ -164,6 +173,8 @@ pub async fn update_weight_handler( let mut cover_image = None; let mut description_markdown = None; let mut description_rendered_html = None; + let mut ietf_language_tag = None; + let mut ietf_primary_language_subtag = None; if let Some(title) = &request.title { if contains_slurs(title) { @@ -205,6 +216,30 @@ pub async fn update_weight_handler( description_rendered_html = Some(html); } + if request.language_tag.is_some() { + // Only voice models have a language. + match weight.weights_type { + WeightsType::Tacotron2 => {} + WeightsType::GptSoVits => {} + WeightsType::SoVitsSvc => {} + WeightsType::RvcV2 => {} + WeightsType::HifiganTacotron2 => {} + WeightsType::VallE => {} + _ => { + return Err(UpdateWeightError::BadInput("Language tag is not applicable to this model type".to_string())); + } + } + } + + if let Some(language_tag) = request.language_tag.as_deref().map(|t| t.trim()) { + if let Some(canonical_tag) = get_canonicalized_language_tag_for_model(language_tag) { + if let Some(primary_language_subtag) = get_primary_language_subtag(canonical_tag) { + ietf_language_tag = Some(canonical_tag.to_string()); + ietf_primary_language_subtag = Some(primary_language_subtag); + } + } + } + let query_result = update_weights(UpdateWeightArgs { weight_token: &ModelWeightToken::new(path.weight_token.clone()), title: weight_title.as_deref(), @@ -212,6 +247,8 @@ pub async fn update_weight_handler( maybe_description_markdown: description_markdown.as_deref(), maybe_description_rendered_html: description_rendered_html.as_deref(), creator_set_visibility: request.visibility.as_ref(), + ietf_language_tag: ietf_language_tag.as_deref(), + ietf_primary_language_subtag: ietf_primary_language_subtag.as_deref(), transactor: Transactor::for_connection(&mut mysql_connection), }).await;