From 0811e12c0b6dd5fa06bb4d14649e33ded61a4580 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Sun, 21 Jan 2024 01:10:20 -0500 Subject: [PATCH] port legacy GET TTS endpoint to model weights --- .../tts_tables/tts_models.sql | 1 + .../get_tts_model_info_migration.rs | 250 ++++++++++++++ .../lib/migration/src/text_to_speech/mod.rs | 5 +- .../get/get_weight_for_legacy_tts_info.rs | 325 ++++++++++++++++++ .../src/queries/model_weights/get/mod.rs | 1 + .../lib/redis_common/src/redis_cache_keys.rs | 6 +- .../endpoints/tts/get_tts_model.rs | 141 ++++---- 7 files changed, 660 insertions(+), 69 deletions(-) create mode 100644 crates/lib/migration/src/text_to_speech/get_tts_model_info_migration.rs create mode 100644 crates/lib/mysql_queries/src/queries/model_weights/get/get_weight_for_legacy_tts_info.rs diff --git a/_sql/migrations_squashed/tts_tables/tts_models.sql b/_sql/migrations_squashed/tts_tables/tts_models.sql index ca6c71e565..2a057938eb 100644 --- a/_sql/migrations_squashed/tts_tables/tts_models.sql +++ b/_sql/migrations_squashed/tts_tables/tts_models.sql @@ -43,6 +43,7 @@ CREATE TABLE tts_models ( has_self_contained_pitch_model BOOLEAN NOT NULL DEFAULT FALSE, -- NB(2022-07-05): THIS IS NOW MEANINGLESS AND SUPERSEDED BY `TEXT_PIPELINE_TYPE`. + -- NB(2024-01-20): All 8720 records in the database are "basic". -- NB: DO NOT CHANGE ORDER; APPEND ONLY! -- How text should be handled. text_preprocessing_algorithm ENUM( diff --git a/crates/lib/migration/src/text_to_speech/get_tts_model_info_migration.rs b/crates/lib/migration/src/text_to_speech/get_tts_model_info_migration.rs new file mode 100644 index 0000000000..a24c2ba77b --- /dev/null +++ b/crates/lib/migration/src/text_to_speech/get_tts_model_info_migration.rs @@ -0,0 +1,250 @@ +use chrono::{DateTime, Utc}; +use serde_derive::{Deserialize, Serialize}; +use sqlx::MySql; +use sqlx::pool::PoolConnection; +use enums::by_table::tts_models::tts_model_type::TtsModelType; + +use enums::common::visibility::Visibility; +use errors::AnyhowResult; +use mysql_queries::column_types::vocoder_type::VocoderType; +use mysql_queries::queries::model_weights::get::get_weight_for_legacy_tts_info::{get_weight_for_legacy_tts_info_with_connection, ModelWeightForLegacyTtsInfo}; +use mysql_queries::queries::tts::tts_models::get_tts_model::{get_tts_model_by_token_using_connection, TtsModelRecord}; +use tokens::tokens::model_weights::ModelWeightToken; + +/// Get TTS model +/// This is for the tts model info page +pub async fn get_tts_model_info_migration( + token: &str, + mysql_connection: &mut PoolConnection, + can_see_deleted: bool, + use_weights_table: bool, +) -> AnyhowResult> { + // NB: This is temporary migration code as we switch from the `tts_models` table to the `model_weights` table. + if use_weights_table { + let token = ModelWeightToken::new_from_str(token); + + let maybe_model = get_weight_for_legacy_tts_info_with_connection( + &token, + can_see_deleted, + mysql_connection + ).await?; + + Ok(maybe_model.map(|model| TtsModelInfoMigration::ModelWeight(model))) + + } else { + let maybe_model = get_tts_model_by_token_using_connection( + &token, + true, + mysql_connection + ).await?; + + Ok(maybe_model.map(|model| TtsModelInfoMigration::LegacyTts(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, Serialize, Deserialize)] +pub enum TtsModelInfoMigration { + /// Old type from the `tts_models` table, on the way out + LegacyTts(TtsModelRecord), + /// New type, replacing the `tts_models` table. + ModelWeight(ModelWeightForLegacyTtsInfo), +} + +impl TtsModelInfoMigration { + pub fn token(&self) -> &str { + match self { + Self::LegacyTts(ref model) => model.model_token.as_str(), + Self::ModelWeight(ref model) => model.token.as_str(), + } + } + + pub fn title(&self) -> &str { + match self { + Self::LegacyTts(ref model) => &model.title, + Self::ModelWeight(ref model) => &model.title, + } + } + + pub fn ietf_language_tag(&self) -> &str { + match self { + Self::LegacyTts(ref model) => &model.ietf_language_tag, + Self::ModelWeight(ref model) => model.maybe_ietf_language_tag.as_deref().unwrap_or("en"), + } + } + + pub fn ietf_primary_language_subtag(&self) -> &str { + match self { + Self::LegacyTts(ref model) => &model.ietf_primary_language_subtag, + Self::ModelWeight(ref model) => model.maybe_ietf_primary_language_subtag.as_deref().unwrap_or("en"), + } + } + + pub fn creator_user_token(&self) -> &str { + match self { + Self::LegacyTts(ref model) => &model.creator_user_token, + Self::ModelWeight(ref model) => model.creator_user_token.as_str(), + } + } + + pub fn creator_username(&self) -> &str { + match self { + Self::LegacyTts(ref model) => &model.creator_username, + Self::ModelWeight(ref model) => &model.creator_username, + } + } + + pub fn creator_display_name(&self) -> &str { + match self { + Self::LegacyTts(ref model) => &model.creator_display_name, + Self::ModelWeight(ref model) => &model.creator_display_name, + } + } + + pub fn creator_gravatar_hash(&self) -> &str { + match self { + Self::LegacyTts(ref model) => &model.creator_gravatar_hash, + Self::ModelWeight(ref model) => &model.creator_gravatar_hash, + } + } + + pub fn creator_set_visibility(&self) -> Visibility{ + match self { + Self::LegacyTts(ref model) => model.creator_set_visibility, + Self::ModelWeight(ref model) => model.creator_set_visibility, + } + } + + pub fn created_at(&self) -> &DateTime { + match self { + Self::LegacyTts(ref model) => &model.created_at, + Self::ModelWeight(ref model) => &model.created_at, + } + } + + pub fn updated_at(&self) -> &DateTime { + match self { + Self::LegacyTts(ref model) => &model.updated_at, + Self::ModelWeight(ref model) => &model.updated_at, + } + } + + // Not supported in the new table + pub fn is_front_page_featured(&self) -> bool { + match self { + Self::LegacyTts(ref model) => model.is_front_page_featured, + Self::ModelWeight(ref _model) => false, + } + } + + // Not supported in the new table + pub fn is_twitch_featured(&self) -> bool { + match self { + Self::LegacyTts(ref model) => model.is_twitch_featured, + Self::ModelWeight(ref _model) => false, + } + } + + // Not supported in the new table + pub fn is_locked_from_use(&self) -> bool { + match self { + Self::LegacyTts(ref model) => model.is_locked_from_use, + Self::ModelWeight(ref _model) => false, + } + } + + // Not supported in the new table + pub fn is_locked_from_user_modification(&self) -> bool { + match self { + Self::LegacyTts(ref model) => model.is_locked_from_user_modification, + Self::ModelWeight(ref _model) => false, + } + } + + // Not supported in the new table + pub fn user_ratings_positive_count(&self) -> u32 { + match self { + Self::LegacyTts(ref model) => model.user_ratings_positive_count, + Self::ModelWeight(ref _model) => 0, + } + } + + // Not supported in the new table + pub fn user_ratings_negative_count(&self) -> u32 { + match self { + Self::LegacyTts(ref model) => model.user_ratings_negative_count, + Self::ModelWeight(ref _model) => 0, + } + } + + // Not supported in the new table + pub fn user_ratings_total_count(&self) -> u32 { + match self { + Self::LegacyTts(ref model) => model.user_ratings_total_count, + Self::ModelWeight(ref _model) => 0, + } + } + + // Not supported in the new table + pub fn maybe_suggested_unique_bot_command(&self) -> Option<&str> { + match self { + Self::LegacyTts(ref model) => model.maybe_suggested_unique_bot_command.as_deref(), + Self::ModelWeight(ref _model) => None, + } + } + + pub fn tts_model_type(&self) -> TtsModelType { + match self { + Self::LegacyTts(ref model) => model.tts_model_type, + Self::ModelWeight(ref _model) => TtsModelType::Tacotron2, // NB: Always TT2 + } + } + + pub fn description_markdown(&self) -> &str { + match self { + Self::LegacyTts(ref model) => &model.description_markdown, + Self::ModelWeight(ref model) => &model.maybe_description_markdown.as_deref().unwrap_or(""), + } + } + + pub fn description_rendered_html(&self) -> &str { + match self { + Self::LegacyTts(ref model) => &model.description_rendered_html, + Self::ModelWeight(ref model) => &model.maybe_description_rendered_html.as_deref().unwrap_or(""), + } + } + + pub fn maybe_default_pretrained_vocoder(&self) -> Option { + match self { + Self::LegacyTts(ref model) => model.maybe_default_pretrained_vocoder, + Self::ModelWeight(ref model) => model.maybe_default_pretrained_vocoder, + } + } + + + pub fn text_preprocessing_algorithm(&self) -> &str { + match self { + Self::LegacyTts(ref model) => &model.text_preprocessing_algorithm, + Self::ModelWeight(ref _model) => "basic", // NB: All records in the DB are "basic" + } + } + + /* NB(bt, 2024-01-20): Breakdown of the text_pipeline_type values in the DB: + mysql> select text_pipeline_type , count(*) from tts_models group by text_pipeline_type ; + +--------------------+----------+ + | text_pipeline_type | count(*) | + +--------------------+----------+ + | NULL | 4406 | + | legacy_fakeyou | 2572 | + | english_v1 | 1548 | + | spanish_v2 | 194 | + +--------------------+----------+ + */ + pub fn text_pipeline_type(&self) -> Option<&str> { + match self { + Self::LegacyTts(ref model) => model.text_pipeline_type.as_deref(), + Self::ModelWeight(ref model) => model.maybe_text_pipeline_type.as_deref(), + } + } +} diff --git a/crates/lib/migration/src/text_to_speech/mod.rs b/crates/lib/migration/src/text_to_speech/mod.rs index 7f23b44bf1..a26935efbd 100644 --- a/crates/lib/migration/src/text_to_speech/mod.rs +++ b/crates/lib/migration/src/text_to_speech/mod.rs @@ -1,2 +1,3 @@ -pub mod list_tts_models_for_migration; -pub mod get_tts_model_for_inference_migration; \ No newline at end of file +pub mod get_tts_model_for_inference_migration; +pub mod get_tts_model_info_migration; +pub mod list_tts_models_for_migration; \ No newline at end of file diff --git a/crates/lib/mysql_queries/src/queries/model_weights/get/get_weight_for_legacy_tts_info.rs b/crates/lib/mysql_queries/src/queries/model_weights/get/get_weight_for_legacy_tts_info.rs new file mode 100644 index 0000000000..8377ad693f --- /dev/null +++ b/crates/lib/mysql_queries/src/queries/model_weights/get/get_weight_for_legacy_tts_info.rs @@ -0,0 +1,325 @@ +use anyhow::anyhow; +use chrono::{DateTime, Utc}; +use log::error; +use sqlx::{MySql, MySqlPool}; +use sqlx::pool::PoolConnection; + +use container_common::anyhow_result::AnyhowResult; +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::{model_weights::ModelWeightToken, users::UserToken}; +use crate::column_types::vocoder_type::VocoderType; + +#[derive(Serialize, Deserialize, Clone)] +pub struct ModelWeightForLegacyTtsInfo { + pub token: ModelWeightToken, + pub title: String, + pub weights_type: WeightsType, + pub weights_category: WeightsCategory, + pub maybe_description_markdown: Option, + pub maybe_description_rendered_html: Option, + + 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, + pub file_size_bytes: i32, + pub file_checksum_sha2: String, + pub public_bucket_hash: String, + pub maybe_public_bucket_prefix: Option, + pub maybe_public_bucket_extension: Option, + + pub maybe_cover_image_public_bucket_hash: Option, + pub maybe_cover_image_public_bucket_prefix: Option, + pub maybe_cover_image_public_bucket_extension: Option, + + pub maybe_ratings_positive_count: Option, + pub maybe_ratings_negative_count: Option, + pub maybe_bookmark_count: Option, + + pub maybe_ietf_language_tag: Option, + pub maybe_ietf_primary_language_subtag: Option, + pub maybe_default_pretrained_vocoder: Option, + pub maybe_text_pipeline_type: 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 get_weight_for_legacy_tts_info( + weight_token: &ModelWeightToken, + can_see_deleted: bool, + mysql_pool: &MySqlPool +) -> AnyhowResult> { + let mut connection = mysql_pool.acquire().await?; + get_weight_for_legacy_tts_info_with_connection(weight_token, can_see_deleted, &mut connection).await +} + +pub async fn get_weight_for_legacy_tts_info_with_connection( + weight_token: &ModelWeightToken, + can_see_deleted: bool, + mysql_connection: &mut PoolConnection +) -> AnyhowResult> { + let maybe_result = if can_see_deleted { + select_include_deleted(weight_token, mysql_connection).await + } else { + select_without_deleted(weight_token, mysql_connection).await + }; + + let record: RawWeight = match maybe_result { + Ok(record) => record, + Err(sqlx::Error::RowNotFound) => { + return Ok(None); + } + Err(err) => { + error!("Error fetching weights by token: {:?}", err); + return Err(anyhow!("Error fetching weights by token: {:?}", err)); + } + }; + + // unwrap the result + + Ok( + Some(ModelWeightForLegacyTtsInfo { + token: record.token, + title: record.title, + weights_type: record.weights_type, + weights_category: record.weights_category, + maybe_description_markdown: record.maybe_description_markdown, + maybe_description_rendered_html: record.maybe_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, + original_download_url: record.original_download_url, + original_filename: record.original_filename, + file_size_bytes: record.file_size_bytes, + file_checksum_sha2: record.file_checksum_sha2, + 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_cover_image_public_bucket_hash: record.maybe_cover_image_public_bucket_hash, + maybe_cover_image_public_bucket_prefix: record.maybe_cover_image_public_bucket_prefix, + maybe_cover_image_public_bucket_extension: record.maybe_cover_image_public_bucket_extension, + maybe_ratings_positive_count: record.maybe_ratings_positive_count, + maybe_ratings_negative_count: record.maybe_ratings_negative_count, + maybe_bookmark_count: record.maybe_bookmark_count, + maybe_ietf_language_tag: record.maybe_ietf_language_tag, + maybe_ietf_primary_language_subtag: record.maybe_ietf_primary_language_subtag, + maybe_default_pretrained_vocoder: record.maybe_default_pretrained_vocoder, + maybe_text_pipeline_type: record.maybe_text_pipeline_type, + version: record.version, + created_at: record.created_at, + updated_at: record.updated_at, + user_deleted_at: record.user_deleted_at, + mod_deleted_at: record.mod_deleted_at, + }) + ) +} + +async fn select_include_deleted( + weight_token: &ModelWeightToken, + mysql_connection: &mut PoolConnection +) -> Result { + sqlx + ::query_as!( + RawWeight, + r#" + SELECT + wt.token as `token: tokens::tokens::model_weights::ModelWeightToken`, + wt.title, + wt.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`, + wt.weights_category as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`, + wt.maybe_description_markdown, + wt.maybe_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`, + wt.original_download_url, + wt.original_filename, + wt.file_size_bytes, + wt.file_checksum_sha2, + + wt.public_bucket_hash, + wt.maybe_public_bucket_prefix, + wt.maybe_public_bucket_extension, + + cover_image.public_bucket_directory_hash as maybe_cover_image_public_bucket_hash, + cover_image.maybe_public_bucket_prefix as maybe_cover_image_public_bucket_prefix, + cover_image.maybe_public_bucket_extension as maybe_cover_image_public_bucket_extension, + + entity_stats.ratings_positive_count as maybe_ratings_positive_count, + entity_stats.ratings_negative_count as maybe_ratings_negative_count, + entity_stats.bookmark_count as maybe_bookmark_count, + + w_extension.ietf_language_tag as maybe_ietf_language_tag, + w_extension.ietf_primary_language_subtag as maybe_ietf_primary_language_subtag, + w_extension.maybe_default_pretrained_vocoder as `maybe_default_pretrained_vocoder: crate::column_types::vocoder_type::VocoderType`, + w_extension.text_pipeline_type as maybe_text_pipeline_type, + + wt.version, + wt.created_at, + wt.updated_at, + 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 cover_image + ON cover_image.token = wt.maybe_cover_image_media_file_token + LEFT OUTER JOIN entity_stats + ON entity_stats.entity_type = "model_weight" + AND entity_stats.entity_token = wt.token + + LEFT OUTER JOIN model_weights_extension_tts_details as w_extension + ON w_extension.model_weights_token = wt.token + + WHERE + wt.token = ? + "#, + weight_token.as_str() + ) + .fetch_one(&mut **mysql_connection).await +} + +async fn select_without_deleted( + weight_token: &ModelWeightToken, + mysql_connection: &mut PoolConnection +) -> Result { + //as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`, + //as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory` + sqlx + ::query_as!( + RawWeight, + r#" + SELECT + wt.token as `token: tokens::tokens::model_weights::ModelWeightToken`, + wt.title, + wt.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`, + wt.weights_category as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`, + wt.maybe_description_markdown, + wt.maybe_description_rendered_html, + 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, + wt.file_size_bytes, + wt.file_checksum_sha2, + wt.public_bucket_hash, + wt.maybe_public_bucket_prefix, + wt.maybe_public_bucket_extension, + + cover_image.public_bucket_directory_hash as maybe_cover_image_public_bucket_hash, + cover_image.maybe_public_bucket_prefix as maybe_cover_image_public_bucket_prefix, + cover_image.maybe_public_bucket_extension as maybe_cover_image_public_bucket_extension, + + entity_stats.ratings_positive_count as maybe_ratings_positive_count, + entity_stats.ratings_negative_count as maybe_ratings_negative_count, + entity_stats.bookmark_count as maybe_bookmark_count, + + w_extension.ietf_language_tag as maybe_ietf_language_tag, + w_extension.ietf_primary_language_subtag as maybe_ietf_primary_language_subtag, + w_extension.maybe_default_pretrained_vocoder as `maybe_default_pretrained_vocoder: crate::column_types::vocoder_type::VocoderType`, + w_extension.text_pipeline_type as maybe_text_pipeline_type, + + wt.version, + wt.created_at, + wt.updated_at, + 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 cover_image + ON cover_image.token = wt.maybe_cover_image_media_file_token + LEFT OUTER JOIN entity_stats + ON entity_stats.entity_type = "model_weight" + AND entity_stats.entity_token = wt.token + + LEFT OUTER JOIN model_weights_extension_tts_details as w_extension + ON w_extension.model_weights_token = wt.token + + WHERE + wt.token = ? + AND wt.user_deleted_at IS NULL + AND wt.mod_deleted_at IS NULL + "#, + weight_token.as_str() + ) + .fetch_one(&mut **mysql_connection).await +} + +// RawWeight is the struct that is returned from the database in raw form. +#[derive(Serialize)] +pub struct RawWeight { + pub token: ModelWeightToken, + pub title: String, + pub weights_type: WeightsType, + pub weights_category: WeightsCategory, + pub maybe_description_markdown: Option, + pub maybe_description_rendered_html: Option, + + 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, + pub file_size_bytes: i32, + pub file_checksum_sha2: String, + pub public_bucket_hash: String, + pub maybe_public_bucket_prefix: Option, + pub maybe_public_bucket_extension: Option, + + pub maybe_cover_image_public_bucket_hash: Option, + pub maybe_cover_image_public_bucket_prefix: Option, + pub maybe_cover_image_public_bucket_extension: Option, + + pub maybe_ratings_positive_count: Option, + pub maybe_ratings_negative_count: Option, + pub maybe_bookmark_count: Option, + + pub maybe_ietf_language_tag: Option, + pub maybe_ietf_primary_language_subtag: Option, + pub maybe_default_pretrained_vocoder: Option, + pub maybe_text_pipeline_type: 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/model_weights/get/mod.rs b/crates/lib/mysql_queries/src/queries/model_weights/get/mod.rs index 4a49c2d43d..2a6378f982 100644 --- a/crates/lib/mysql_queries/src/queries/model_weights/get/mod.rs +++ b/crates/lib/mysql_queries/src/queries/model_weights/get/mod.rs @@ -1,2 +1,3 @@ pub mod get_weight; pub mod get_weight_for_legacy_tts_enqueue; +pub mod get_weight_for_legacy_tts_info; diff --git a/crates/lib/redis_common/src/redis_cache_keys.rs b/crates/lib/redis_common/src/redis_cache_keys.rs index a2afba5f5f..de7338c46d 100644 --- a/crates/lib/redis_common/src/redis_cache_keys.rs +++ b/crates/lib/redis_common/src/redis_cache_keys.rs @@ -9,8 +9,12 @@ impl RedisCacheKeys { format!("get_tts_model:{}", model_token) } + pub fn get_tts_model_for_info_migration_endpoint(model_token: &str) -> String { + format!("get_tts_inf1:{}", model_token) + } + pub fn get_tts_model_for_inference_migration_endpoint(model_token: &str) -> String { - format!("get_tts_inf:{}", model_token) + format!("get_tts_inf2:{}", model_token) } pub fn get_unified_queue_stats_endpoint() -> &'static str { diff --git a/crates/service/web/storyteller_web/src/http_server/endpoints/tts/get_tts_model.rs b/crates/service/web/storyteller_web/src/http_server/endpoints/tts/get_tts_model.rs index 2c4f1d9d82..7e7bfa084f 100644 --- a/crates/service/web/storyteller_web/src/http_server/endpoints/tts/get_tts_model.rs +++ b/crates/service/web/storyteller_web/src/http_server/endpoints/tts/get_tts_model.rs @@ -16,8 +16,8 @@ use log::warn; use enums::by_table::tts_models::tts_model_type::TtsModelType; use enums::common::visibility::Visibility; use http_server_common::response::serialize_as_json_error::serialize_as_json_error; +use migration::text_to_speech::get_tts_model_info_migration::get_tts_model_info_migration; use mysql_queries::column_types::vocoder_type::VocoderType; -use mysql_queries::queries::tts::tts_models::get_tts_model::get_tts_model_by_token_using_connection; use redis_common::redis_cache_keys::RedisCacheKeys; use tts_common::text_pipelines::guess_pipeline::guess_text_pipeline_heuristic; use tts_common::text_pipelines::text_pipeline_type::TextPipelineType; @@ -204,13 +204,16 @@ pub async fn get_tts_model_handler( let model_token = path.token.clone(); + let switch_to_weights_flag = server_state.flags.switch_tts_to_model_weights; + let get_tts_model = move || { // NB: async closures are not yet stable in Rust, so we include an async block. async move { - get_tts_model_by_token_using_connection( + get_tts_model_info_migration( &model_token, - show_deleted_models, &mut mysql_connection, + show_deleted_models, + switch_to_weights_flag, ).await } }; @@ -221,14 +224,14 @@ pub async fn get_tts_model_handler( get_tts_model().await } Ok(mut redis_ttl_cache) => { - let cache_key = RedisCacheKeys::get_tts_model_endpoint(&path.token); + let cache_key = RedisCacheKeys::get_tts_model_for_info_migration_endpoint(&path.token); redis_ttl_cache.lazy_load_if_not_cached(&cache_key, move || { get_tts_model() }).await } }; - let mut model = match model_query_result { + let model = match model_query_result { Err(e) => { warn!("query error: {:?}", e); return Err(GetTtsModelError::ServerError); @@ -238,22 +241,24 @@ pub async fn get_tts_model_handler( }; if let Some(user_session) = &maybe_user_session { - is_original_author = user_session.user_token == model.creator_user_token; + is_original_author = user_session.user_token == model.creator_user_token(); } - if let Some(moderator_fields) = model.maybe_moderator_fields.as_ref() { - // NB: The moderator fields will always be present before removal - // We don't want non-mods seeing stuff made by banned users. - if moderator_fields.creator_is_banned && !is_moderator { - return Err(GetTtsModelError::NotFound); - } - } + // NB(bt, 2024-01-20): Removing to make porting easier. + //if let Some(moderator_fields) = model.maybe_moderator_fields.as_ref() { + // // NB: The moderator fields will always be present before removal + // // We don't want non-mods seeing stuff made by banned users. + // if moderator_fields.creator_is_banned && !is_moderator { + // return Err(GetTtsModelError::NotFound); + // } + //} - if !is_moderator { - model.maybe_moderator_fields = None; - } + // NB(bt, 2024-01-20): Removing to make porting easier. + //if !is_moderator { + // model.maybe_moderator_fields = None; + //} - let text_pipeline_type = model.text_pipeline_type + let text_pipeline_type = model.text_pipeline_type() .as_deref() .and_then(|pipeline_type| { // If there's an error deserializing, turn it to None instead of 500ing. The column is @@ -273,64 +278,68 @@ pub async fn get_tts_model_handler( // TODO: Use language to infer as well. let text_pipeline_type_guess = - guess_text_pipeline_heuristic(Some(model.created_at.clone())); + guess_text_pipeline_heuristic(Some(model.created_at().clone())); // Map to public response type. let response = GetTtsModelSuccessResponse { success: true, model: TtsModelInfo { - model_token: model.model_token, - tts_model_type: model.tts_model_type, + model_token: model.token().to_string(), + tts_model_type: model.tts_model_type(), text_pipeline_type, text_pipeline_type_guess, - maybe_custom_vocoder: match model.maybe_custom_vocoder { - None => None, - Some(vocoder) => Some(CustomVocoderInfo { - vocoder_token: vocoder.vocoder_token, - vocoder_title: vocoder.vocoder_title, - creator_user_token: vocoder.creator_user_token, - creator_username: vocoder.creator_username, - creator_display_name: vocoder.creator_display_name, - creator_gravatar_hash: vocoder.creator_gravatar_hash, - }) - }, - maybe_default_pretrained_vocoder: model.maybe_default_pretrained_vocoder, - text_preprocessing_algorithm: model.text_preprocessing_algorithm, - creator_user_token: model.creator_user_token, - creator_username: model.creator_username.to_string(), // NB: Cloned because of ref use for avatar below - creator_display_name: model.creator_display_name, - creator_gravatar_hash: model.creator_gravatar_hash, - creator_default_avatar_index: default_avatar_from_username(&model.creator_username), - creator_default_avatar_color_index: default_avatar_color_from_username(&model.creator_username), - 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, - is_front_page_featured: model.is_front_page_featured, - is_twitch_featured: model.is_twitch_featured, - maybe_suggested_unique_bot_command: model.maybe_suggested_unique_bot_command, + // NB(bt, 2024-01-20): We won't be needing these much longer. + maybe_custom_vocoder: None, + //maybe_custom_vocoder: match model.maybe_custom_vocoder { + // None => None, + // Some(vocoder) => Some(CustomVocoderInfo { + // vocoder_token: vocoder.vocoder_token, + // vocoder_title: vocoder.vocoder_title, + // creator_user_token: vocoder.creator_user_token, + // creator_username: vocoder.creator_username, + // creator_display_name: vocoder.creator_display_name, + // creator_gravatar_hash: vocoder.creator_gravatar_hash, + // }) + //}, + maybe_default_pretrained_vocoder: model.maybe_default_pretrained_vocoder(), + text_preprocessing_algorithm: model.text_preprocessing_algorithm().to_string(), + creator_user_token: model.creator_user_token().to_string(), + creator_username: model.creator_username().to_string(), // NB: Cloned because of ref use for avatar below + creator_display_name: model.creator_display_name().to_string(), + creator_gravatar_hash: model.creator_gravatar_hash().to_string(), + creator_default_avatar_index: default_avatar_from_username(&model.creator_username().to_string()), + creator_default_avatar_color_index: default_avatar_color_from_username(&model.creator_username().to_string()), + title: model.title().to_string(), + description_markdown: model.description_markdown().to_string(), + description_rendered_html: model.description_rendered_html().to_string(), + ietf_language_tag: model.ietf_language_tag().to_string(), + ietf_primary_language_subtag: model.ietf_primary_language_subtag().to_string(), + is_front_page_featured: model.is_front_page_featured(), + is_twitch_featured: model.is_twitch_featured(), + maybe_suggested_unique_bot_command: model.maybe_suggested_unique_bot_command().map(|s| s.to_string()), user_ratings: UserRatingsStats { - positive_count: model.user_ratings_positive_count, - negative_count: model.user_ratings_negative_count, - total_count: model.user_ratings_total_count, + positive_count: model.user_ratings_positive_count(), + negative_count: model.user_ratings_negative_count(), + total_count: model.user_ratings_total_count(), }, - creator_set_visibility: model.creator_set_visibility, - is_locked_from_use: model.is_locked_from_use, - is_locked_from_user_modification: model.is_locked_from_user_modification, - created_at: model.created_at, - updated_at: model.updated_at, - maybe_moderator_fields: model.maybe_moderator_fields.map(|mod_fields| { - TtsModelModeratorFieldInfo { - use_default_m_factor: mod_fields.use_default_mel_multiply_factor, - maybe_custom_m_factor: mod_fields.maybe_custom_mel_multiply_factor, - creator_is_banned: mod_fields.creator_is_banned, - creator_ip_address_creation: mod_fields.creator_ip_address_creation, - creator_ip_address_last_update: mod_fields.creator_ip_address_last_update, - user_deleted_at: mod_fields.user_deleted_at, - mod_deleted_at: mod_fields.mod_deleted_at, - } - }) + creator_set_visibility: model.creator_set_visibility(), + is_locked_from_use: model.is_locked_from_use(), + is_locked_from_user_modification: model.is_locked_from_user_modification(), + created_at: model.created_at().clone(), + updated_at: model.updated_at().clone(), + maybe_moderator_fields: None, + // NB(bt, 2024-01-20): We won't be needing these much longer. + //maybe_moderator_fields: model.maybe_moderator_fields.map(|mod_fields| { + // TtsModelModeratorFieldInfo { + // use_default_m_factor: mod_fields.use_default_mel_multiply_factor, + // maybe_custom_m_factor: mod_fields.maybe_custom_mel_multiply_factor, + // creator_is_banned: mod_fields.creator_is_banned, + // creator_ip_address_creation: mod_fields.creator_ip_address_creation, + // creator_ip_address_last_update: mod_fields.creator_ip_address_last_update, + // user_deleted_at: mod_fields.user_deleted_at, + // mod_deleted_at: mod_fields.mod_deleted_at, + // } + //}) }, };