mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-06 06:14:52 -05:00
Compare commits
1
Commits
mdawg
..
bt-ffprobe
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cf9f1bdd93 |
@@ -26,14 +26,14 @@ MIGRATION_DIRECTORY=_sql/migrations/
|
||||
# Bucket config (non-secret)
|
||||
REGION_NAME=us-east1
|
||||
|
||||
#TTS_DOWNLOAD_BUCKET_NAME=kasisnu-t
|
||||
#TTS_DOWNLOAD_BUCKET_ROOT=/user_uploaded_tts_models
|
||||
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
|
||||
W2L_PRIVATE_DOWNLOAD_BUCKET_NAME=dev-vocodes-private-uploads
|
||||
W2L_PUBLIC_DOWNLOAD_BUCKET_NAME=dev-vocodes-public
|
||||
|
||||
#PRIVATE_BUCKET_NAME=kasisnu-test-area-private
|
||||
#PUBLIC_BUCKET_NAME=kasisnu-test-area-public
|
||||
PRIVATE_BUCKET_NAME=dev-vocodes-private-uploads
|
||||
PUBLIC_BUCKET_NAME=dev-vocodes-public
|
||||
|
||||
# Bucket roots
|
||||
AUDIO_UPLOADS_BUCKET_ROOT=/user_uploaded_w2l_audio
|
||||
@@ -64,7 +64,7 @@ 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"
|
||||
|
||||
#; DOWNLOAD_SCRIPT="/home/tensor/code/storyteller/web-downloader/.venv/bin/python3.11 /home/tensor/code/storyteller/web-downloader/download_internet_file.py"
|
||||
DOWNLOAD_SCRIPT="/home/tensor/code/storyteller/web-downloader/.venv/bin/python3.11 /home/tensor/code/storyteller/web-downloader/download_internet_file.py"
|
||||
|
||||
TTS_INFERENCE_SIDECAR_HOSTNAME=localhost:8000
|
||||
|
||||
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nSELECT\n maybe_model_type as queue_type,\n count(*) as pending_job_count,\n NOW() as present_time\n FROM (\n SELECT\n token,\n maybe_model_type\n FROM generic_inference_jobs\n WHERE status IN (\"pending\", \"attempt_failed\")\n AND maybe_model_type IS NOT NULL\n UNION\n SELECT\n token,\n maybe_model_type\n FROM generic_inference_jobs\n WHERE status IN (\"started\")\n AND created_at > (CURDATE() - INTERVAL 15 MINUTE)\n AND maybe_model_type IS NOT NULL\n) as generic_inner\nGROUP BY queue_type\nUNION\nSELECT\n \"legacy_tts\" as queue_type,\n count(*) as pending_job_count,\n NOW() as present_time\nFROM (\n SELECT\n token\n FROM tts_inference_jobs\n WHERE status IN (\"pending\", \"attempt_failed\")\n UNION\n SELECT\n token\n FROM tts_inference_jobs\n WHERE status IN (\"started\")\n AND created_at > (CURDATE() - INTERVAL 15 MINUTE)\n) as legacy_inner\nGROUP BY queue_type\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "queue_type",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "pending_job_count",
|
||||
"type_info": {
|
||||
"type": "LongLong",
|
||||
"flags": "NOT_NULL | BINARY",
|
||||
"char_set": 63,
|
||||
"max_size": 21
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "present_time",
|
||||
"type_info": {
|
||||
"type": "Datetime",
|
||||
"flags": "NOT_NULL",
|
||||
"char_set": 224,
|
||||
"max_size": 76
|
||||
}
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 0
|
||||
},
|
||||
"nullable": [
|
||||
true,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "074307d7cd5c9a6f27e4d5ecce3072dcd13914a6f7f5f27f0f7232ae6c4813b4"
|
||||
}
|
||||
+3
-14
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nSELECT\n token as `token: tokens::tokens::users::UserToken`,\n username,\n email_address,\n password_hash as `password_hash: crate::queries::users::user::lookup_user_for_login_result::VecBytes`,\n password_version,\n is_banned,\n maybe_feature_flags\nFROM users\nWHERE username = ?\nLIMIT 1\n ",
|
||||
"query": "\nSELECT\n token as `token: tokens::tokens::users::UserToken`,\n username,\n email_address,\n password_hash as `password_hash: crate::queries::users::user::lookup_user_for_login_result::VecBytes`,\n password_version,\n is_banned\nFROM users\nWHERE username = ?\nLIMIT 1\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -62,16 +62,6 @@
|
||||
"char_set": 63,
|
||||
"max_size": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"name": "maybe_feature_flags",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 1020
|
||||
}
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
@@ -83,9 +73,8 @@
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "8e577db7abde571a0f29fc9d678891349918f0882136d9f7a39b338f66270f11"
|
||||
"hash": "5795b8579a458706077b1fa95e4627b90eac6606bde543b6406233d081fd0eb5"
|
||||
}
|
||||
-47
@@ -1,47 +0,0 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nSELECT\n job_type as queue_type,\n count(*) as pending_job_count,\n NOW() as present_time\n FROM (\n SELECT\n token,\n job_type\n FROM generic_inference_jobs\n WHERE status IN (\"pending\", \"attempt_failed\")\n AND job_type IS NOT NULL\n UNION\n SELECT\n token,\n job_type\n FROM generic_inference_jobs\n WHERE status IN (\"started\")\n AND created_at > (CURDATE() - INTERVAL 15 MINUTE)\n AND job_type IS NOT NULL\n) as generic_inner\nGROUP BY queue_type\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "queue_type",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "pending_job_count",
|
||||
"type_info": {
|
||||
"type": "LongLong",
|
||||
"flags": "NOT_NULL | BINARY",
|
||||
"char_set": 63,
|
||||
"max_size": 21
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "present_time",
|
||||
"type_info": {
|
||||
"type": "Datetime",
|
||||
"flags": "NOT_NULL | BINARY",
|
||||
"char_set": 63,
|
||||
"max_size": 19
|
||||
}
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 0
|
||||
},
|
||||
"nullable": [
|
||||
true,
|
||||
false,
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "73dc054488b2fa3efc923d3a90914a1450b73e99a377562484a0498ccce1676f"
|
||||
}
|
||||
+3
-14
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nSELECT\n jobs.token as `job_token: tokens::tokens::generic_inference_jobs::InferenceJobToken`,\n\n jobs.status as `status: enums::common::job_status_plus::JobStatusPlus`,\n jobs.attempt_count,\n\n jobs.maybe_creator_user_token as `maybe_creator_user_token: tokens::tokens::users::UserToken`,\n jobs.maybe_creator_anonymous_visitor_token as `maybe_creator_anonymous_visitor_token: tokens::tokens::anonymous_visitor_tracking::AnonymousVisitorTrackingToken`,\n jobs.creator_ip_address,\n\n jobs.inference_category as `inference_category: enums::by_table::generic_inference_jobs::inference_category::InferenceCategory`,\n jobs.maybe_model_type,\n jobs.maybe_model_token,\n jobs.maybe_raw_inference_text,\n jobs.maybe_inference_args,\n\n jobs.frontend_failure_category as `maybe_frontend_failure_category: enums::by_table::generic_inference_jobs::frontend_failure_category::FrontendFailureCategory`,\n\n jobs.on_success_result_entity_type as maybe_result_entity_type,\n jobs.on_success_result_entity_token as maybe_result_entity_token,\n\n model_weights.title as maybe_model_weights_title,\n tts_models.title as maybe_tts_model_title,\n voice_conversion_models.title as maybe_voice_conversion_model_title,\n\n tts_results.public_bucket_wav_audio_path as maybe_tts_public_bucket_path,\n voice_conversion_results.public_bucket_hash as maybe_voice_conversion_public_bucket_hash,\n\n media_files.public_bucket_directory_hash as maybe_media_file_public_bucket_directory_hash,\n media_files.maybe_public_bucket_prefix as maybe_media_file_public_bucket_prefix,\n media_files.maybe_public_bucket_extension as maybe_media_file_public_bucket_extension,\n\n jobs.assigned_worker as maybe_assigned_worker,\n jobs.assigned_cluster as maybe_assigned_cluster,\n\n jobs.is_keepalive_required,\n\n jobs.created_at,\n jobs.updated_at,\n\n jobs.first_started_at as maybe_first_started_at,\n jobs.successfully_completed_at as maybe_successfully_completed_at,\n\n NOW() as database_clock\n\nFROM generic_inference_jobs as jobs\n\nLEFT OUTER JOIN model_weights ON jobs.maybe_model_token = model_weights.token\nLEFT OUTER JOIN tts_models ON jobs.maybe_model_token = tts_models.token\nLEFT OUTER JOIN voice_conversion_models ON jobs.maybe_model_token = voice_conversion_models.token\n\nLEFT OUTER JOIN tts_results ON jobs.on_success_result_entity_token = tts_results.token\nLEFT OUTER JOIN voice_conversion_results ON jobs.on_success_result_entity_token = voice_conversion_results.token\nLEFT OUTER JOIN media_files ON jobs.on_success_result_entity_token = media_files.token\n\nWHERE jobs.token = ?\n ",
|
||||
"query": "\nSELECT\n jobs.token as `job_token: tokens::tokens::generic_inference_jobs::InferenceJobToken`,\n\n jobs.status as `status: enums::common::job_status_plus::JobStatusPlus`,\n jobs.attempt_count,\n\n jobs.maybe_creator_user_token as `maybe_creator_user_token: tokens::tokens::users::UserToken`,\n jobs.maybe_creator_anonymous_visitor_token as `maybe_creator_anonymous_visitor_token: tokens::tokens::anonymous_visitor_tracking::AnonymousVisitorTrackingToken`,\n jobs.creator_ip_address,\n\n jobs.inference_category as `inference_category: enums::by_table::generic_inference_jobs::inference_category::InferenceCategory`,\n jobs.maybe_model_type,\n jobs.maybe_model_token,\n jobs.maybe_raw_inference_text,\n jobs.maybe_inference_args,\n\n jobs.frontend_failure_category as `maybe_frontend_failure_category: enums::by_table::generic_inference_jobs::frontend_failure_category::FrontendFailureCategory`,\n\n jobs.on_success_result_entity_type as maybe_result_entity_type,\n jobs.on_success_result_entity_token as maybe_result_entity_token,\n\n model_weights.title as maybe_model_weights_title,\n tts_models.title as maybe_tts_model_title,\n voice_conversion_models.title as maybe_voice_conversion_model_title,\n\n tts_results.public_bucket_wav_audio_path as maybe_tts_public_bucket_path,\n voice_conversion_results.public_bucket_hash as maybe_voice_conversion_public_bucket_hash,\n\n media_files.public_bucket_directory_hash as maybe_media_file_public_bucket_directory_hash,\n media_files.maybe_public_bucket_prefix as maybe_media_file_public_bucket_prefix,\n media_files.maybe_public_bucket_extension as maybe_media_file_public_bucket_extension,\n\n jobs.assigned_worker as maybe_assigned_worker,\n jobs.assigned_cluster as maybe_assigned_cluster,\n\n jobs.is_keepalive_required,\n\n jobs.created_at,\n jobs.updated_at,\n\n jobs.first_started_at as maybe_first_started_at,\n jobs.successfully_completed_at as maybe_successfully_completed_at\n\nFROM generic_inference_jobs as jobs\n\nLEFT OUTER JOIN model_weights ON jobs.maybe_model_token = model_weights.token\nLEFT OUTER JOIN tts_models ON jobs.maybe_model_token = tts_models.token\nLEFT OUTER JOIN voice_conversion_models ON jobs.maybe_model_token = voice_conversion_models.token\n\nLEFT OUTER JOIN tts_results ON jobs.on_success_result_entity_token = tts_results.token\nLEFT OUTER JOIN voice_conversion_results ON jobs.on_success_result_entity_token = voice_conversion_results.token\nLEFT OUTER JOIN media_files ON jobs.on_success_result_entity_token = media_files.token\n\nWHERE jobs.token = ?\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -292,16 +292,6 @@
|
||||
"char_set": 63,
|
||||
"max_size": 19
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 29,
|
||||
"name": "database_clock",
|
||||
"type_info": {
|
||||
"type": "Datetime",
|
||||
"flags": "NOT_NULL | BINARY",
|
||||
"char_set": 63,
|
||||
"max_size": 19
|
||||
}
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
@@ -336,9 +326,8 @@
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
false
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "e5121d132d93ec43e48197e00b19040a50ff2942224dc70b0faa0ec988aee7cf"
|
||||
"hash": "7d5030b221e9b470ee7af4b73539fd2ef477e6f3c98c56422016449c6775222d"
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nUPDATE media_files\nSET\n maybe_animation_type = ?\nWHERE\n token = ?\nLIMIT 1\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 2
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "930cfd52f78fa14a86bd1a67c5fe36d8c8961079b2bd684a0d4da315bf3ce16e"
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nUPDATE generic_inference_jobs\nSET\n is_dismissed_by_user = TRUE\nWHERE maybe_creator_user_token = ?\nAND status IN (\n 'dead',\n 'cancelled_by_system',\n 'cancelled_by_user',\n 'complete_failure',\n 'complete_success'\n )\nAND created_at > DATE_SUB(NOW(), INTERVAL 36 HOUR)\nLIMIT 1000\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "a1d44611ee4a0ecc54548f95719f01341eb242460c79ef75423de96b31ed5385"
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nINSERT INTO users (\n token,\n username,\n display_name,\n email_address,\n email_gravatar_hash,\n profile_markdown,\n profile_rendered_html,\n user_role_slug,\n password_hash,\n ip_address_creation,\n ip_address_last_login,\n ip_address_last_update,\n can_access_studio\n)\nVALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? , ?)\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 13
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "a3066dd68c77b5381104a754b2774506990f659c9a0ed2de1fcb8e6fd953e726"
|
||||
}
|
||||
-12
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nUPDATE media_files\nSET\n maybe_engine_category = ?\nWHERE\n token = ?\nLIMIT 1\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 2
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "b56ee40be840cdec013f3f99eb585e4ac333ccfe563ba3da4c9a80df33dccd57"
|
||||
}
|
||||
+39
-50
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nSELECT\n m.token as `token: tokens::tokens::media_files::MediaFileToken`,\n\n m.media_class as `media_class: enums::by_table::media_files::media_file_class::MediaFileClass`,\n m.media_type as `media_type: enums::by_table::media_files::media_file_type::MediaFileType`,\n\n m.maybe_engine_category as `maybe_engine_category: enums::by_table::media_files::media_file_engine_category::MediaFileEngineCategory`,\n m.maybe_animation_type as `maybe_animation_type: enums::by_table::media_files::media_file_animation_type::MediaFileAnimationType`,\n\n m.maybe_media_subtype as `maybe_media_subtype: enums::by_table::media_files::media_file_subtype::MediaFileSubtype`,\n\n m.maybe_mime_type,\n\n users.token as `maybe_creator_user_token: tokens::tokens::users::UserToken`,\n users.username as maybe_creator_username,\n users.display_name as maybe_creator_display_name,\n users.email_gravatar_hash as maybe_creator_gravatar_hash,\n\n m.maybe_creator_anonymous_visitor_token as `maybe_creator_anonymous_visitor_token: tokens::tokens::anonymous_visitor_tracking::AnonymousVisitorTrackingToken`,\n\n m.maybe_batch_token as `maybe_batch_token: tokens::tokens::batch_generations::BatchGenerationToken`,\n\n m.maybe_style_transfer_source_media_file_token as `maybe_style_transfer_source_media_file_token: tokens::tokens::media_files::MediaFileToken`,\n m.maybe_scene_source_media_file_token as `maybe_scene_source_media_file_token: tokens::tokens::media_files::MediaFileToken`,\n\n m.maybe_title,\n m.maybe_text_transcript,\n\n m.maybe_origin_filename,\n\n m.maybe_duration_millis,\n\n m.maybe_prompt_token as `maybe_prompt_token: tokens::tokens::prompts::PromptToken`,\n prompts.maybe_other_args as maybe_other_prompt_args,\n\n media_file_cover_image.public_bucket_directory_hash as maybe_file_cover_image_public_bucket_hash,\n media_file_cover_image.maybe_public_bucket_prefix as maybe_file_cover_image_public_bucket_prefix,\n media_file_cover_image.maybe_public_bucket_extension as maybe_file_cover_image_public_bucket_extension,\n\n m.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n\n model_weights.token as `maybe_model_weights_token: tokens::tokens::model_weights::ModelWeightToken`,\n model_weights.title as maybe_model_weights_title,\n model_weights.weights_type as `maybe_model_weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n model_weights.weights_category as `maybe_model_weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n\n model_weight_cover_image.public_bucket_directory_hash as maybe_model_cover_image_public_bucket_hash,\n model_weight_cover_image.maybe_public_bucket_prefix as maybe_model_cover_image_public_bucket_prefix,\n model_weight_cover_image.maybe_public_bucket_extension as maybe_model_cover_image_public_bucket_extension,\n\n model_weight_creator.token as `maybe_model_weight_creator_user_token: tokens::tokens::users::UserToken`,\n model_weight_creator.username as maybe_model_weight_creator_username,\n model_weight_creator.display_name as maybe_model_weight_creator_display_name,\n model_weight_creator.email_gravatar_hash as maybe_model_weight_creator_gravatar_hash,\n\n m.public_bucket_directory_hash,\n m.maybe_public_bucket_prefix,\n m.maybe_public_bucket_extension,\n\n entity_stats.ratings_positive_count as maybe_ratings_positive_count,\n entity_stats.ratings_negative_count as maybe_ratings_negative_count,\n entity_stats.bookmark_count as maybe_bookmark_count,\n\n featured_items.entity_token IS NOT NULL AS is_featured,\n\n m.created_at,\n m.updated_at\n\nFROM media_files AS m\nLEFT OUTER JOIN users\n ON m.maybe_creator_user_token = users.token\nLEFT OUTER JOIN model_weights\n ON m.maybe_origin_model_token = model_weights.token\nLEFT OUTER JOIN media_files as media_file_cover_image\n ON media_file_cover_image.token = m.maybe_cover_image_media_file_token\nLEFT OUTER JOIN media_files as model_weight_cover_image\n ON model_weight_cover_image.token = model_weights.maybe_cover_image_media_file_token\nLEFT OUTER JOIN users as model_weight_creator\n ON model_weight_creator.token = model_weights.creator_user_token\nLEFT OUTER JOIN entity_stats\n ON entity_stats.entity_type = \"media_file\"\n AND entity_stats.entity_token = m.token\nLEFT OUTER JOIN prompts\n ON prompts.token = m.maybe_prompt_token\nLEFT OUTER JOIN featured_items\n ON featured_items.entity_type = 'media_file'\n AND featured_items.entity_token = m.token\n AND featured_items.deleted_at IS NULL\nWHERE\n m.token = ?\n ",
|
||||
"query": "\nSELECT\n m.token as `token: tokens::tokens::media_files::MediaFileToken`,\n\n m.media_class as `media_class: enums::by_table::media_files::media_file_class::MediaFileClass`,\n m.media_type as `media_type: enums::by_table::media_files::media_file_type::MediaFileType`,\n\n m.maybe_engine_category as `maybe_engine_category: enums::by_table::media_files::media_file_engine_category::MediaFileEngineCategory`,\n m.maybe_animation_type as `maybe_animation_type: enums::by_table::media_files::media_file_animation_type::MediaFileAnimationType`,\n\n m.maybe_media_subtype as `maybe_media_subtype: enums::by_table::media_files::media_file_subtype::MediaFileSubtype`,\n\n users.token as `maybe_creator_user_token: tokens::tokens::users::UserToken`,\n users.username as maybe_creator_username,\n users.display_name as maybe_creator_display_name,\n users.email_gravatar_hash as maybe_creator_gravatar_hash,\n\n m.maybe_creator_anonymous_visitor_token as `maybe_creator_anonymous_visitor_token: tokens::tokens::anonymous_visitor_tracking::AnonymousVisitorTrackingToken`,\n\n m.maybe_batch_token as `maybe_batch_token: tokens::tokens::batch_generations::BatchGenerationToken`,\n\n m.maybe_style_transfer_source_media_file_token as `maybe_style_transfer_source_media_file_token: tokens::tokens::media_files::MediaFileToken`,\n m.maybe_scene_source_media_file_token as `maybe_scene_source_media_file_token: tokens::tokens::media_files::MediaFileToken`,\n\n\n m.maybe_title,\n m.maybe_text_transcript,\n\n m.maybe_origin_filename,\n\n m.maybe_duration_millis,\n\n m.maybe_prompt_token as `maybe_prompt_token: tokens::tokens::prompts::PromptToken`,\n prompts.maybe_other_args as maybe_other_prompt_args,\n\n media_file_cover_image.public_bucket_directory_hash as maybe_file_cover_image_public_bucket_hash,\n media_file_cover_image.maybe_public_bucket_prefix as maybe_file_cover_image_public_bucket_prefix,\n media_file_cover_image.maybe_public_bucket_extension as maybe_file_cover_image_public_bucket_extension,\n\n m.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n\n model_weights.token as `maybe_model_weights_token: tokens::tokens::model_weights::ModelWeightToken`,\n model_weights.title as maybe_model_weights_title,\n model_weights.weights_type as `maybe_model_weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n model_weights.weights_category as `maybe_model_weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n\n model_weight_cover_image.public_bucket_directory_hash as maybe_model_cover_image_public_bucket_hash,\n model_weight_cover_image.maybe_public_bucket_prefix as maybe_model_cover_image_public_bucket_prefix,\n model_weight_cover_image.maybe_public_bucket_extension as maybe_model_cover_image_public_bucket_extension,\n\n model_weight_creator.token as `maybe_model_weight_creator_user_token: tokens::tokens::users::UserToken`,\n model_weight_creator.username as maybe_model_weight_creator_username,\n model_weight_creator.display_name as maybe_model_weight_creator_display_name,\n model_weight_creator.email_gravatar_hash as maybe_model_weight_creator_gravatar_hash,\n\n m.public_bucket_directory_hash,\n m.maybe_public_bucket_prefix,\n m.maybe_public_bucket_extension,\n\n entity_stats.ratings_positive_count as maybe_ratings_positive_count,\n entity_stats.ratings_negative_count as maybe_ratings_negative_count,\n entity_stats.bookmark_count as maybe_bookmark_count,\n\n featured_items.entity_token IS NOT NULL AS is_featured,\n\n m.created_at,\n m.updated_at\n\nFROM media_files AS m\nLEFT OUTER JOIN users\n ON m.maybe_creator_user_token = users.token\nLEFT OUTER JOIN model_weights\n ON m.maybe_origin_model_token = model_weights.token\nLEFT OUTER JOIN media_files as media_file_cover_image\n ON media_file_cover_image.token = m.maybe_cover_image_media_file_token\nLEFT OUTER JOIN media_files as model_weight_cover_image\n ON model_weight_cover_image.token = model_weights.maybe_cover_image_media_file_token\nLEFT OUTER JOIN users as model_weight_creator\n ON model_weight_creator.token = model_weights.creator_user_token\nLEFT OUTER JOIN entity_stats\n ON entity_stats.entity_type = \"media_file\"\n AND entity_stats.entity_token = m.token\nLEFT OUTER JOIN prompts\n ON prompts.token = m.maybe_prompt_token\nLEFT OUTER JOIN featured_items\n ON featured_items.entity_type = 'media_file'\n AND featured_items.entity_token = m.token\n AND featured_items.deleted_at IS NULL\nWHERE\n m.token = ?\n AND m.user_deleted_at IS NULL\n AND m.mod_deleted_at IS NULL\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -65,16 +65,6 @@
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"name": "maybe_mime_type",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"name": "maybe_creator_user_token: tokens::tokens::users::UserToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -84,7 +74,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"ordinal": 7,
|
||||
"name": "maybe_creator_username",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -94,7 +84,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 9,
|
||||
"ordinal": 8,
|
||||
"name": "maybe_creator_display_name",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -104,7 +94,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 10,
|
||||
"ordinal": 9,
|
||||
"name": "maybe_creator_gravatar_hash",
|
||||
"type_info": {
|
||||
"type": "String",
|
||||
@@ -114,7 +104,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 11,
|
||||
"ordinal": 10,
|
||||
"name": "maybe_creator_anonymous_visitor_token: tokens::tokens::anonymous_visitor_tracking::AnonymousVisitorTrackingToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -124,7 +114,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 12,
|
||||
"ordinal": 11,
|
||||
"name": "maybe_batch_token: tokens::tokens::batch_generations::BatchGenerationToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -134,7 +124,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 13,
|
||||
"ordinal": 12,
|
||||
"name": "maybe_style_transfer_source_media_file_token: tokens::tokens::media_files::MediaFileToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -144,7 +134,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 14,
|
||||
"ordinal": 13,
|
||||
"name": "maybe_scene_source_media_file_token: tokens::tokens::media_files::MediaFileToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -154,7 +144,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 15,
|
||||
"ordinal": 14,
|
||||
"name": "maybe_title",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -164,7 +154,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 16,
|
||||
"ordinal": 15,
|
||||
"name": "maybe_text_transcript",
|
||||
"type_info": {
|
||||
"type": "Blob",
|
||||
@@ -174,7 +164,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 17,
|
||||
"ordinal": 16,
|
||||
"name": "maybe_origin_filename",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -184,7 +174,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 18,
|
||||
"ordinal": 17,
|
||||
"name": "maybe_duration_millis",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
@@ -194,7 +184,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 19,
|
||||
"ordinal": 18,
|
||||
"name": "maybe_prompt_token: tokens::tokens::prompts::PromptToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -204,7 +194,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 20,
|
||||
"ordinal": 19,
|
||||
"name": "maybe_other_prompt_args",
|
||||
"type_info": {
|
||||
"type": "Blob",
|
||||
@@ -214,7 +204,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 21,
|
||||
"ordinal": 20,
|
||||
"name": "maybe_file_cover_image_public_bucket_hash",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -224,7 +214,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 22,
|
||||
"ordinal": 21,
|
||||
"name": "maybe_file_cover_image_public_bucket_prefix",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -234,7 +224,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 23,
|
||||
"ordinal": 22,
|
||||
"name": "maybe_file_cover_image_public_bucket_extension",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -244,7 +234,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 24,
|
||||
"ordinal": 23,
|
||||
"name": "creator_set_visibility: enums::common::visibility::Visibility",
|
||||
"type_info": {
|
||||
"type": "String",
|
||||
@@ -254,7 +244,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 25,
|
||||
"ordinal": 24,
|
||||
"name": "maybe_model_weights_token: tokens::tokens::model_weights::ModelWeightToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -264,7 +254,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 26,
|
||||
"ordinal": 25,
|
||||
"name": "maybe_model_weights_title",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -274,7 +264,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 27,
|
||||
"ordinal": 26,
|
||||
"name": "maybe_model_weights_type: enums::by_table::model_weights::weights_types::WeightsType",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -284,7 +274,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 28,
|
||||
"ordinal": 27,
|
||||
"name": "maybe_model_weights_category: enums::by_table::model_weights::weights_category::WeightsCategory",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -294,7 +284,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 29,
|
||||
"ordinal": 28,
|
||||
"name": "maybe_model_cover_image_public_bucket_hash",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -304,7 +294,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 30,
|
||||
"ordinal": 29,
|
||||
"name": "maybe_model_cover_image_public_bucket_prefix",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -314,7 +304,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 31,
|
||||
"ordinal": 30,
|
||||
"name": "maybe_model_cover_image_public_bucket_extension",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -324,7 +314,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 32,
|
||||
"ordinal": 31,
|
||||
"name": "maybe_model_weight_creator_user_token: tokens::tokens::users::UserToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -334,7 +324,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 33,
|
||||
"ordinal": 32,
|
||||
"name": "maybe_model_weight_creator_username",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -344,7 +334,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 34,
|
||||
"ordinal": 33,
|
||||
"name": "maybe_model_weight_creator_display_name",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -354,7 +344,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 35,
|
||||
"ordinal": 34,
|
||||
"name": "maybe_model_weight_creator_gravatar_hash",
|
||||
"type_info": {
|
||||
"type": "String",
|
||||
@@ -364,7 +354,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 36,
|
||||
"ordinal": 35,
|
||||
"name": "public_bucket_directory_hash",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -374,7 +364,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 37,
|
||||
"ordinal": 36,
|
||||
"name": "maybe_public_bucket_prefix",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -384,7 +374,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 38,
|
||||
"ordinal": 37,
|
||||
"name": "maybe_public_bucket_extension",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -394,7 +384,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 39,
|
||||
"ordinal": 38,
|
||||
"name": "maybe_ratings_positive_count",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
@@ -404,7 +394,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 40,
|
||||
"ordinal": 39,
|
||||
"name": "maybe_ratings_negative_count",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
@@ -414,7 +404,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 41,
|
||||
"ordinal": 40,
|
||||
"name": "maybe_bookmark_count",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
@@ -424,7 +414,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 42,
|
||||
"ordinal": 41,
|
||||
"name": "is_featured",
|
||||
"type_info": {
|
||||
"type": "LongLong",
|
||||
@@ -434,7 +424,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 43,
|
||||
"ordinal": 42,
|
||||
"name": "created_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
@@ -444,7 +434,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 44,
|
||||
"ordinal": 43,
|
||||
"name": "updated_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
@@ -481,7 +471,6 @@
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
@@ -505,5 +494,5 @@
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "f1861dc84015b5c753cb5c31313c747386bce56983108fd6a01815d02d429630"
|
||||
"hash": "beda05b1f3e3f78ca2610c491e682ea1c76fb5effccd5d710761353baf8ce161"
|
||||
}
|
||||
+39
-50
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nSELECT\n m.token as `token: tokens::tokens::media_files::MediaFileToken`,\n\n m.media_class as `media_class: enums::by_table::media_files::media_file_class::MediaFileClass`,\n m.media_type as `media_type: enums::by_table::media_files::media_file_type::MediaFileType`,\n\n m.maybe_engine_category as `maybe_engine_category: enums::by_table::media_files::media_file_engine_category::MediaFileEngineCategory`,\n m.maybe_animation_type as `maybe_animation_type: enums::by_table::media_files::media_file_animation_type::MediaFileAnimationType`,\n\n m.maybe_media_subtype as `maybe_media_subtype: enums::by_table::media_files::media_file_subtype::MediaFileSubtype`,\n\n m.maybe_mime_type,\n\n users.token as `maybe_creator_user_token: tokens::tokens::users::UserToken`,\n users.username as maybe_creator_username,\n users.display_name as maybe_creator_display_name,\n users.email_gravatar_hash as maybe_creator_gravatar_hash,\n\n m.maybe_creator_anonymous_visitor_token as `maybe_creator_anonymous_visitor_token: tokens::tokens::anonymous_visitor_tracking::AnonymousVisitorTrackingToken`,\n\n m.maybe_batch_token as `maybe_batch_token: tokens::tokens::batch_generations::BatchGenerationToken`,\n\n m.maybe_style_transfer_source_media_file_token as `maybe_style_transfer_source_media_file_token: tokens::tokens::media_files::MediaFileToken`,\n m.maybe_scene_source_media_file_token as `maybe_scene_source_media_file_token: tokens::tokens::media_files::MediaFileToken`,\n\n\n m.maybe_title,\n m.maybe_text_transcript,\n\n m.maybe_origin_filename,\n\n m.maybe_duration_millis,\n\n m.maybe_prompt_token as `maybe_prompt_token: tokens::tokens::prompts::PromptToken`,\n prompts.maybe_other_args as maybe_other_prompt_args,\n\n media_file_cover_image.public_bucket_directory_hash as maybe_file_cover_image_public_bucket_hash,\n media_file_cover_image.maybe_public_bucket_prefix as maybe_file_cover_image_public_bucket_prefix,\n media_file_cover_image.maybe_public_bucket_extension as maybe_file_cover_image_public_bucket_extension,\n\n m.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n\n model_weights.token as `maybe_model_weights_token: tokens::tokens::model_weights::ModelWeightToken`,\n model_weights.title as maybe_model_weights_title,\n model_weights.weights_type as `maybe_model_weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n model_weights.weights_category as `maybe_model_weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n\n model_weight_cover_image.public_bucket_directory_hash as maybe_model_cover_image_public_bucket_hash,\n model_weight_cover_image.maybe_public_bucket_prefix as maybe_model_cover_image_public_bucket_prefix,\n model_weight_cover_image.maybe_public_bucket_extension as maybe_model_cover_image_public_bucket_extension,\n\n model_weight_creator.token as `maybe_model_weight_creator_user_token: tokens::tokens::users::UserToken`,\n model_weight_creator.username as maybe_model_weight_creator_username,\n model_weight_creator.display_name as maybe_model_weight_creator_display_name,\n model_weight_creator.email_gravatar_hash as maybe_model_weight_creator_gravatar_hash,\n\n m.public_bucket_directory_hash,\n m.maybe_public_bucket_prefix,\n m.maybe_public_bucket_extension,\n\n entity_stats.ratings_positive_count as maybe_ratings_positive_count,\n entity_stats.ratings_negative_count as maybe_ratings_negative_count,\n entity_stats.bookmark_count as maybe_bookmark_count,\n\n featured_items.entity_token IS NOT NULL AS is_featured,\n\n m.created_at,\n m.updated_at\n\nFROM media_files AS m\nLEFT OUTER JOIN users\n ON m.maybe_creator_user_token = users.token\nLEFT OUTER JOIN model_weights\n ON m.maybe_origin_model_token = model_weights.token\nLEFT OUTER JOIN media_files as media_file_cover_image\n ON media_file_cover_image.token = m.maybe_cover_image_media_file_token\nLEFT OUTER JOIN media_files as model_weight_cover_image\n ON model_weight_cover_image.token = model_weights.maybe_cover_image_media_file_token\nLEFT OUTER JOIN users as model_weight_creator\n ON model_weight_creator.token = model_weights.creator_user_token\nLEFT OUTER JOIN entity_stats\n ON entity_stats.entity_type = \"media_file\"\n AND entity_stats.entity_token = m.token\nLEFT OUTER JOIN prompts\n ON prompts.token = m.maybe_prompt_token\nLEFT OUTER JOIN featured_items\n ON featured_items.entity_type = 'media_file'\n AND featured_items.entity_token = m.token\n AND featured_items.deleted_at IS NULL\nWHERE\n m.token = ?\n AND m.user_deleted_at IS NULL\n AND m.mod_deleted_at IS NULL\n ",
|
||||
"query": "\nSELECT\n m.token as `token: tokens::tokens::media_files::MediaFileToken`,\n\n m.media_class as `media_class: enums::by_table::media_files::media_file_class::MediaFileClass`,\n m.media_type as `media_type: enums::by_table::media_files::media_file_type::MediaFileType`,\n\n m.maybe_engine_category as `maybe_engine_category: enums::by_table::media_files::media_file_engine_category::MediaFileEngineCategory`,\n m.maybe_animation_type as `maybe_animation_type: enums::by_table::media_files::media_file_animation_type::MediaFileAnimationType`,\n\n m.maybe_media_subtype as `maybe_media_subtype: enums::by_table::media_files::media_file_subtype::MediaFileSubtype`,\n\n users.token as `maybe_creator_user_token: tokens::tokens::users::UserToken`,\n users.username as maybe_creator_username,\n users.display_name as maybe_creator_display_name,\n users.email_gravatar_hash as maybe_creator_gravatar_hash,\n\n m.maybe_creator_anonymous_visitor_token as `maybe_creator_anonymous_visitor_token: tokens::tokens::anonymous_visitor_tracking::AnonymousVisitorTrackingToken`,\n\n m.maybe_batch_token as `maybe_batch_token: tokens::tokens::batch_generations::BatchGenerationToken`,\n\n m.maybe_style_transfer_source_media_file_token as `maybe_style_transfer_source_media_file_token: tokens::tokens::media_files::MediaFileToken`,\n m.maybe_scene_source_media_file_token as `maybe_scene_source_media_file_token: tokens::tokens::media_files::MediaFileToken`,\n\n m.maybe_title,\n m.maybe_text_transcript,\n\n m.maybe_origin_filename,\n\n m.maybe_duration_millis,\n\n m.maybe_prompt_token as `maybe_prompt_token: tokens::tokens::prompts::PromptToken`,\n prompts.maybe_other_args as maybe_other_prompt_args,\n\n media_file_cover_image.public_bucket_directory_hash as maybe_file_cover_image_public_bucket_hash,\n media_file_cover_image.maybe_public_bucket_prefix as maybe_file_cover_image_public_bucket_prefix,\n media_file_cover_image.maybe_public_bucket_extension as maybe_file_cover_image_public_bucket_extension,\n\n m.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n\n model_weights.token as `maybe_model_weights_token: tokens::tokens::model_weights::ModelWeightToken`,\n model_weights.title as maybe_model_weights_title,\n model_weights.weights_type as `maybe_model_weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n model_weights.weights_category as `maybe_model_weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n\n model_weight_cover_image.public_bucket_directory_hash as maybe_model_cover_image_public_bucket_hash,\n model_weight_cover_image.maybe_public_bucket_prefix as maybe_model_cover_image_public_bucket_prefix,\n model_weight_cover_image.maybe_public_bucket_extension as maybe_model_cover_image_public_bucket_extension,\n\n model_weight_creator.token as `maybe_model_weight_creator_user_token: tokens::tokens::users::UserToken`,\n model_weight_creator.username as maybe_model_weight_creator_username,\n model_weight_creator.display_name as maybe_model_weight_creator_display_name,\n model_weight_creator.email_gravatar_hash as maybe_model_weight_creator_gravatar_hash,\n\n m.public_bucket_directory_hash,\n m.maybe_public_bucket_prefix,\n m.maybe_public_bucket_extension,\n\n entity_stats.ratings_positive_count as maybe_ratings_positive_count,\n entity_stats.ratings_negative_count as maybe_ratings_negative_count,\n entity_stats.bookmark_count as maybe_bookmark_count,\n\n featured_items.entity_token IS NOT NULL AS is_featured,\n\n m.created_at,\n m.updated_at\n\nFROM media_files AS m\nLEFT OUTER JOIN users\n ON m.maybe_creator_user_token = users.token\nLEFT OUTER JOIN model_weights\n ON m.maybe_origin_model_token = model_weights.token\nLEFT OUTER JOIN media_files as media_file_cover_image\n ON media_file_cover_image.token = m.maybe_cover_image_media_file_token\nLEFT OUTER JOIN media_files as model_weight_cover_image\n ON model_weight_cover_image.token = model_weights.maybe_cover_image_media_file_token\nLEFT OUTER JOIN users as model_weight_creator\n ON model_weight_creator.token = model_weights.creator_user_token\nLEFT OUTER JOIN entity_stats\n ON entity_stats.entity_type = \"media_file\"\n AND entity_stats.entity_token = m.token\nLEFT OUTER JOIN prompts\n ON prompts.token = m.maybe_prompt_token\nLEFT OUTER JOIN featured_items\n ON featured_items.entity_type = 'media_file'\n AND featured_items.entity_token = m.token\n AND featured_items.deleted_at IS NULL\nWHERE\n m.token = ?\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -65,16 +65,6 @@
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"name": "maybe_mime_type",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"name": "maybe_creator_user_token: tokens::tokens::users::UserToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -84,7 +74,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"ordinal": 7,
|
||||
"name": "maybe_creator_username",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -94,7 +84,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 9,
|
||||
"ordinal": 8,
|
||||
"name": "maybe_creator_display_name",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -104,7 +94,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 10,
|
||||
"ordinal": 9,
|
||||
"name": "maybe_creator_gravatar_hash",
|
||||
"type_info": {
|
||||
"type": "String",
|
||||
@@ -114,7 +104,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 11,
|
||||
"ordinal": 10,
|
||||
"name": "maybe_creator_anonymous_visitor_token: tokens::tokens::anonymous_visitor_tracking::AnonymousVisitorTrackingToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -124,7 +114,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 12,
|
||||
"ordinal": 11,
|
||||
"name": "maybe_batch_token: tokens::tokens::batch_generations::BatchGenerationToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -134,7 +124,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 13,
|
||||
"ordinal": 12,
|
||||
"name": "maybe_style_transfer_source_media_file_token: tokens::tokens::media_files::MediaFileToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -144,7 +134,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 14,
|
||||
"ordinal": 13,
|
||||
"name": "maybe_scene_source_media_file_token: tokens::tokens::media_files::MediaFileToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -154,7 +144,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 15,
|
||||
"ordinal": 14,
|
||||
"name": "maybe_title",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -164,7 +154,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 16,
|
||||
"ordinal": 15,
|
||||
"name": "maybe_text_transcript",
|
||||
"type_info": {
|
||||
"type": "Blob",
|
||||
@@ -174,7 +164,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 17,
|
||||
"ordinal": 16,
|
||||
"name": "maybe_origin_filename",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -184,7 +174,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 18,
|
||||
"ordinal": 17,
|
||||
"name": "maybe_duration_millis",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
@@ -194,7 +184,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 19,
|
||||
"ordinal": 18,
|
||||
"name": "maybe_prompt_token: tokens::tokens::prompts::PromptToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -204,7 +194,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 20,
|
||||
"ordinal": 19,
|
||||
"name": "maybe_other_prompt_args",
|
||||
"type_info": {
|
||||
"type": "Blob",
|
||||
@@ -214,7 +204,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 21,
|
||||
"ordinal": 20,
|
||||
"name": "maybe_file_cover_image_public_bucket_hash",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -224,7 +214,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 22,
|
||||
"ordinal": 21,
|
||||
"name": "maybe_file_cover_image_public_bucket_prefix",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -234,7 +224,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 23,
|
||||
"ordinal": 22,
|
||||
"name": "maybe_file_cover_image_public_bucket_extension",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -244,7 +234,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 24,
|
||||
"ordinal": 23,
|
||||
"name": "creator_set_visibility: enums::common::visibility::Visibility",
|
||||
"type_info": {
|
||||
"type": "String",
|
||||
@@ -254,7 +244,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 25,
|
||||
"ordinal": 24,
|
||||
"name": "maybe_model_weights_token: tokens::tokens::model_weights::ModelWeightToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -264,7 +254,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 26,
|
||||
"ordinal": 25,
|
||||
"name": "maybe_model_weights_title",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -274,7 +264,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 27,
|
||||
"ordinal": 26,
|
||||
"name": "maybe_model_weights_type: enums::by_table::model_weights::weights_types::WeightsType",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -284,7 +274,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 28,
|
||||
"ordinal": 27,
|
||||
"name": "maybe_model_weights_category: enums::by_table::model_weights::weights_category::WeightsCategory",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -294,7 +284,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 29,
|
||||
"ordinal": 28,
|
||||
"name": "maybe_model_cover_image_public_bucket_hash",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -304,7 +294,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 30,
|
||||
"ordinal": 29,
|
||||
"name": "maybe_model_cover_image_public_bucket_prefix",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -314,7 +304,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 31,
|
||||
"ordinal": 30,
|
||||
"name": "maybe_model_cover_image_public_bucket_extension",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -324,7 +314,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 32,
|
||||
"ordinal": 31,
|
||||
"name": "maybe_model_weight_creator_user_token: tokens::tokens::users::UserToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -334,7 +324,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 33,
|
||||
"ordinal": 32,
|
||||
"name": "maybe_model_weight_creator_username",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -344,7 +334,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 34,
|
||||
"ordinal": 33,
|
||||
"name": "maybe_model_weight_creator_display_name",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -354,7 +344,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 35,
|
||||
"ordinal": 34,
|
||||
"name": "maybe_model_weight_creator_gravatar_hash",
|
||||
"type_info": {
|
||||
"type": "String",
|
||||
@@ -364,7 +354,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 36,
|
||||
"ordinal": 35,
|
||||
"name": "public_bucket_directory_hash",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -374,7 +364,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 37,
|
||||
"ordinal": 36,
|
||||
"name": "maybe_public_bucket_prefix",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -384,7 +374,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 38,
|
||||
"ordinal": 37,
|
||||
"name": "maybe_public_bucket_extension",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
@@ -394,7 +384,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 39,
|
||||
"ordinal": 38,
|
||||
"name": "maybe_ratings_positive_count",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
@@ -404,7 +394,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 40,
|
||||
"ordinal": 39,
|
||||
"name": "maybe_ratings_negative_count",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
@@ -414,7 +404,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 41,
|
||||
"ordinal": 40,
|
||||
"name": "maybe_bookmark_count",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
@@ -424,7 +414,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 42,
|
||||
"ordinal": 41,
|
||||
"name": "is_featured",
|
||||
"type_info": {
|
||||
"type": "LongLong",
|
||||
@@ -434,7 +424,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 43,
|
||||
"ordinal": 42,
|
||||
"name": "created_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
@@ -444,7 +434,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 44,
|
||||
"ordinal": 43,
|
||||
"name": "updated_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
@@ -481,7 +471,6 @@
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
@@ -505,5 +494,5 @@
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "58cb3fd03fb215b1d323f6aa6a5fd713900b9d931700c4226a1d9713b5e469c7"
|
||||
"hash": "bfbe17ad0d993033c1015881f679fc27f5f16fb3edb24e30295c8188ff63d5cd"
|
||||
}
|
||||
+3
-14
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nSELECT\n token as `token: tokens::tokens::users::UserToken`,\n username,\n email_address,\n password_hash as `password_hash: crate::queries::users::user::lookup_user_for_login_result::VecBytes`,\n password_version,\n is_banned,\n maybe_feature_flags\nFROM users\nWHERE email_address = ?\nLIMIT 1\n ",
|
||||
"query": "\nSELECT\n token as `token: tokens::tokens::users::UserToken`,\n username,\n email_address,\n password_hash as `password_hash: crate::queries::users::user::lookup_user_for_login_result::VecBytes`,\n password_version,\n is_banned\nFROM users\nWHERE email_address = ?\nLIMIT 1\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -62,16 +62,6 @@
|
||||
"char_set": 63,
|
||||
"max_size": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"name": "maybe_feature_flags",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 1020
|
||||
}
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
@@ -83,9 +73,8 @@
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
false
|
||||
]
|
||||
},
|
||||
"hash": "48889cc9c9b8dbe482e74687629a6958c1c9bf8a1cd5ae177afea0ad0709736d"
|
||||
"hash": "e8705ee9b3bc3213e806946fef651e9bb8c2cb5cc2ac8eff3eaed82d9a88f90e"
|
||||
}
|
||||
Generated
+1300
-1506
File diff suppressed because it is too large
Load Diff
+4
-2
@@ -7,7 +7,6 @@ members = [
|
||||
"crates/_types/buckets",
|
||||
"crates/_types/composite_identifiers",
|
||||
"crates/_types/enums",
|
||||
"crates/_types/enums_public",
|
||||
"crates/_types/reusable_types", # TODO(bt, 2022-12-21): Deprecate
|
||||
"crates/_types/tokens",
|
||||
|
||||
@@ -28,6 +27,7 @@ members = [
|
||||
"crates/lib/api_clients/cloud_storage",
|
||||
"crates/lib/api_clients/google_drive_common",
|
||||
"crates/lib/api_clients/thumbnail_generator",
|
||||
"crates/lib/api_clients/twitch_common",
|
||||
"crates/lib/bootstrap",
|
||||
"crates/lib/caching/memory_caching",
|
||||
"crates/lib/caching/redis_caching",
|
||||
@@ -60,7 +60,6 @@ members = [
|
||||
"crates/lib/password",
|
||||
"crates/lib/prompt_engineering",
|
||||
"crates/lib/redis_common",
|
||||
"crates/lib/redis_schema",
|
||||
"crates/lib/server_environment",
|
||||
"crates/lib/sqlx_mysql_helpers",
|
||||
"crates/lib/storyteller_root",
|
||||
@@ -83,13 +82,16 @@ members = [
|
||||
"crates/service/job/tts_inference_job",
|
||||
"crates/service/job/w2l_download_job",
|
||||
"crates/service/job/w2l_inference_job",
|
||||
"crates/service/other/twitch_pubsub_subscriber",
|
||||
"crates/service/web/dummy_service",
|
||||
"crates/service/web/storyteller_web",
|
||||
"crates/service/web/websocket_gateway",
|
||||
|
||||
# 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
|
||||
"crates/vendor/limitation",
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
# -*- mode: Python -*-
|
||||
|
||||
if k8s_context() != 'black1':
|
||||
fail("failing early to avoid overwriting prod")
|
||||
local_resource('storyteller-web-binary',
|
||||
cmd='SQLX_OFFLINE=true cargo build --release --bin storyteller-web --target=x86_64-unknown-linux-musl',
|
||||
)
|
||||
|
||||
allow_k8s_contexts('black1')
|
||||
sync_src_crates = sync('./crates', '/storyteller-rust/source/crates')
|
||||
sync_src_sql = sync('./_sql', '/storyteller-rust/source/_sql')
|
||||
sync_src_cargo_lock = sync('./Cargo.lock', '/storyteller-rust/source/Cargo.lock')
|
||||
sync_src_cargo = sync('./Cargo.toml', '/storyteller-rust/source/Cargo.toml')
|
||||
sync_src_env = sync('./.env', '/storyteller-rust/source/.env')
|
||||
sync_src_startup = sync('./_develop/localdev/startup.sh', '/storyteller-rust/_develop/localdev/startup.sh')
|
||||
sync_src_storyteller_binary = sync('./target/x86_64-unknown-linux-musl/release/storyteller-web', '/storyteller-rust/target/x86_64-unknown-linux-musl/release/storyteller-web')
|
||||
docker_build('storyteller-web',
|
||||
'.',
|
||||
dockerfile='_develop/localdev/Dockerfile',
|
||||
platform='linux/amd64',
|
||||
only=[
|
||||
'./target/x86_64-unknown-linux-musl/release/storyteller-web',
|
||||
'_develop/localdev/Dockerfile',
|
||||
'./_develop/localdev/startup.sh',
|
||||
'crates/service/web/storyteller_web/config/storyteller-web.development.env',
|
||||
'_sql', 'diesel.toml', '.env'],
|
||||
live_update = [
|
||||
sync_src_crates,
|
||||
sync_src_sql,
|
||||
sync_src_cargo_lock,
|
||||
sync_src_cargo,
|
||||
sync_src_env,
|
||||
sync_src_startup,
|
||||
sync_src_storyteller_binary,
|
||||
run('date > /restart.txt')
|
||||
],
|
||||
)
|
||||
k8s_yaml('_develop/localdev/kubernetes.yml',
|
||||
|
||||
)
|
||||
k8s_resource(
|
||||
objects=['ssd-hostpath:storageclass', 'test-pvc:persistentvolumeclaim'],
|
||||
new_name='storyteller-web-pvc',
|
||||
trigger_mode=TRIGGER_MODE_MANUAL,
|
||||
)
|
||||
k8s_resource('mysql', port_forwards='3307:3306')
|
||||
k8s_resource('storyteller-web', port_forwards=12345)
|
||||
@@ -6,20 +6,9 @@ RUN apt-get update && \
|
||||
apt-get install -y \
|
||||
mariadb-client \
|
||||
imagemagick \
|
||||
python3-pip \
|
||||
libmariadb-dev \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN cd /tmp && \
|
||||
wget -O entr.zip https://github.com/eradman/entr/archive/refs/tags/5.6.zip && \
|
||||
unzip entr.zip && \
|
||||
cd entr-5.6 && \
|
||||
./configure && \
|
||||
make test && \
|
||||
make install \
|
||||
&& rm -rf /tmp/entr-5.6
|
||||
|
||||
|
||||
|
||||
RUN cargo install diesel_cli --features mysql && \
|
||||
cargo install sqlx-cli --features mysql
|
||||
@@ -30,5 +19,5 @@ ARG GIT_SHA
|
||||
|
||||
RUN echo -n ${GIT_SHA} > /GIT_SHA
|
||||
|
||||
CMD ["/storyteller-rust/_develop/localdev/startup.sh"]
|
||||
CMD ["/storyteller-rust/localdev/startup.sh"]
|
||||
|
||||
|
||||
@@ -27,38 +27,6 @@ spec:
|
||||
ports:
|
||||
- containerPort: 3306
|
||||
|
||||
---
|
||||
apiVersion: storage.k8s.io/v1
|
||||
kind: StorageClass
|
||||
metadata:
|
||||
name: ssd-hostpath
|
||||
provisioner: microk8s.io/hostpath
|
||||
reclaimPolicy: Retain
|
||||
volumeBindingMode: WaitForFirstConsumer
|
||||
parameters:
|
||||
pvDir: /home/kasisnu/microk8s/hostpath-provisioner
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: test-pvc
|
||||
spec:
|
||||
storageClassName: ssd-hostpath
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 10Gi
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: storyteller-config
|
||||
data:
|
||||
buckets.vocodes_bucket_region: us-east1
|
||||
buckets.vocodes_private_bucket_name: kasisnu-test-area-private
|
||||
buckets.vocodes_public_bucket_name: kasisnu-test-area-public
|
||||
|
||||
---
|
||||
|
||||
apiVersion: apps/v1
|
||||
@@ -97,57 +65,29 @@ spec:
|
||||
labels:
|
||||
app: storyteller-web
|
||||
spec:
|
||||
runtimeClassName: nvidia
|
||||
containers:
|
||||
- name: gpt-sovitsdir
|
||||
image: localhost:32000/some-gpt-sovits:latest
|
||||
imagePullPolicy: Always
|
||||
command: ["sleep", "infinity"]
|
||||
resources:
|
||||
limits:
|
||||
nvidia.com/gpu: "1"
|
||||
requests:
|
||||
nvidia.com/gpu: "1"
|
||||
volumeMounts:
|
||||
- mountPath: /application-dir
|
||||
name: application-dir
|
||||
- name: storyteller-web
|
||||
image: storyteller-web:latest
|
||||
imagePullPolicy: Always
|
||||
imagePullPolicy: Never
|
||||
env:
|
||||
- name: MYSQL_URL
|
||||
value: mysql://storyteller:password@mysql/storyteller
|
||||
value: mysql://storyteller:password@mysql.default/storyteller
|
||||
- name: REDIS_0_URL
|
||||
value: redis://redisd@redis/0
|
||||
value: redis://redisd@redis.default/0
|
||||
- name: REDIS_1_URL
|
||||
value: redis://redisd@redis/1
|
||||
value: redis://redisd@redis.default/1
|
||||
- name: ACCESS_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: bucket-secrets
|
||||
key: access-key
|
||||
value: garbage
|
||||
- name: SECRET_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: bucket-secrets
|
||||
key: secret-key
|
||||
value: garbage
|
||||
- name: REGION_NAME
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: storyteller-config
|
||||
key: buckets.vocodes_bucket_region
|
||||
value: garbage
|
||||
- name: W2L_PRIVATE_DOWNLOAD_BUCKET_NAME
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: storyteller-config
|
||||
key: buckets.vocodes_private_bucket_name
|
||||
value: garbage
|
||||
- name: W2L_PUBLIC_DOWNLOAD_BUCKET_NAME
|
||||
valueFrom:
|
||||
configMapKeyRef:
|
||||
name: storyteller-config
|
||||
key: buckets.vocodes_public_bucket_name
|
||||
value: garbage
|
||||
- name: AUDIO_UPLOADS_BUCKET_ROOT
|
||||
value: /user_uploaded_w2l_audio
|
||||
value: garbage
|
||||
- name: TWITCH_USERNAME
|
||||
value: garbage
|
||||
- name: TWITCH_STREAM_KEY
|
||||
@@ -161,14 +101,10 @@ spec:
|
||||
volumeMounts:
|
||||
- mountPath: /storyteller-rust
|
||||
name: storyteller-rust-folder
|
||||
- mountPath: /application-dir
|
||||
name: application-dir
|
||||
volumes:
|
||||
- name: storyteller-rust-folder
|
||||
persistentVolumeClaim:
|
||||
claimName: test-pvc
|
||||
- name: application-dir
|
||||
emptyDir: {}
|
||||
hostPath:
|
||||
path: /storyteller-rust
|
||||
---
|
||||
|
||||
apiVersion: v1
|
||||
@@ -180,7 +116,7 @@ spec:
|
||||
ports:
|
||||
- name: mysql
|
||||
port: 3306
|
||||
nodePort: 32206
|
||||
nodePort: 3306
|
||||
selector:
|
||||
app: mysql
|
||||
|
||||
@@ -195,7 +131,7 @@ spec:
|
||||
ports:
|
||||
- name: redis
|
||||
port: 6379
|
||||
nodePort: 32379
|
||||
nodePort: 6379
|
||||
selector:
|
||||
app: redis
|
||||
|
||||
@@ -210,7 +146,7 @@ spec:
|
||||
ports:
|
||||
- name: storyteller-web
|
||||
port: 12345
|
||||
nodePort: 32345
|
||||
nodePort: 12345
|
||||
selector:
|
||||
app: storyteller-web
|
||||
|
||||
|
||||
@@ -2,8 +2,5 @@
|
||||
set +e +o pipefail
|
||||
diesel migration run --database-url="${MYSQL_URL}"
|
||||
set -e -o pipefail
|
||||
echo 'hello world in startup.sh'
|
||||
#sleep infinity
|
||||
date > /restart.txt
|
||||
echo /restart.txt | entr -nrz /storyteller-rust/target/x86_64-unknown-linux-musl/release/storyteller-web
|
||||
#/storyteller-rust/target/x86_64-unknown-linux-musl/release/storyteller-web
|
||||
./target/x86_64-unknown-linux-musl/release/storyteller-web
|
||||
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
{
|
||||
"settings" : {
|
||||
"index.number_of_shards" : 3,
|
||||
"index.number_of_replicas" : 2
|
||||
},
|
||||
"mappings" : {
|
||||
"properties" : {
|
||||
"token" : { "type" : "keyword" },
|
||||
|
||||
"media_class" : { "type" : "keyword" },
|
||||
"media_type" : { "type" : "keyword" },
|
||||
"maybe_media_subtype" : { "type" : "keyword" },
|
||||
"maybe_engine_category" : { "type" : "keyword" },
|
||||
"maybe_animation_type" : { "type" : "keyword" },
|
||||
|
||||
"maybe_mime_type" : { "type" : "keyword" },
|
||||
|
||||
"public_bucket_hash" : { "type" : "keyword" },
|
||||
"public_bucket_prefix" : { "type" : "keyword" },
|
||||
"public_bucket_extension" : { "type" : "keyword" },
|
||||
|
||||
"creator_set_visibility" : { "type" : "keyword" },
|
||||
|
||||
"maybe_title" : { "type" : "search_as_you_type" },
|
||||
"maybe_title_as_keyword" : { "type" : "keyword" },
|
||||
|
||||
"maybe_cover_image_media_file_token" : { "type" : "keyword" },
|
||||
"maybe_cover_image_public_bucket_hash" : { "type" : "keyword" },
|
||||
"maybe_cover_image_public_bucket_prefix" : { "type" : "keyword" },
|
||||
"maybe_cover_image_public_bucket_extension" : { "type" : "keyword" },
|
||||
|
||||
"maybe_creator_user_token" : { "type" : "keyword" },
|
||||
"maybe_creator_username" : { "type" : "keyword" },
|
||||
"maybe_creator_display_name" : { "type" : "text" },
|
||||
"maybe_creator_gravatar_hash" : { "type" : "text" },
|
||||
|
||||
"created_at" : { "type" : "date" },
|
||||
"updated_at" : { "type" : "date" },
|
||||
"user_deleted_at" : { "type" : "date" },
|
||||
"mod_deleted_at" : { "type" : "date" },
|
||||
|
||||
"is_featured" : {
|
||||
"type": "boolean",
|
||||
"index": true
|
||||
},
|
||||
|
||||
"is_deleted" : {
|
||||
"type": "boolean",
|
||||
"index": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,6 @@
|
||||
"weights_category" : { "type" : "keyword" },
|
||||
|
||||
"title" : { "type" : "search_as_you_type" },
|
||||
"title_as_keyword" : { "type" : "keyword" },
|
||||
|
||||
"maybe_cover_image_media_file_token" : { "type" : "keyword" },
|
||||
"maybe_cover_image_public_bucket_hash" : { "type" : "keyword" },
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
{
|
||||
"query": {
|
||||
"bool": {
|
||||
"must": [
|
||||
{
|
||||
"bool": {
|
||||
"must" : [
|
||||
{
|
||||
"term": {
|
||||
"is_deleted": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"term": {
|
||||
"media_class": "dimensional"
|
||||
}
|
||||
},
|
||||
{
|
||||
"term": {
|
||||
"media_type": "glb"
|
||||
}
|
||||
},
|
||||
{
|
||||
"bool": {
|
||||
"should": [
|
||||
{ "term": { "maybe_engine_category": "object"} },
|
||||
{ "term": { "maybe_engine_category": "image_plane"} }
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"should": [
|
||||
{
|
||||
"fuzzy": {
|
||||
"maybe_title": {
|
||||
"value": "REPLACE_ME",
|
||||
"fuzziness": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"match": {
|
||||
"maybe_title": {
|
||||
"query": "REPLACE_ME",
|
||||
"boost": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"multi_match": {
|
||||
"query": "REPLACE_ME",
|
||||
"type": "bool_prefix",
|
||||
"fields": [
|
||||
"maybe_title",
|
||||
"maybe_title._2gram",
|
||||
"maybe_title._3gram"
|
||||
],
|
||||
"boost": 50
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
{
|
||||
"query": {
|
||||
"bool": {
|
||||
"must": [
|
||||
{
|
||||
"bool": {
|
||||
"should": [
|
||||
{
|
||||
"fuzzy": {
|
||||
"title": {
|
||||
"value": "REPLACE_ME",
|
||||
"fuzziness": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"match": {
|
||||
"title": {
|
||||
"query": "REPLACE_ME",
|
||||
"boost": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"multi_match": {
|
||||
"query": "REPLACE_ME",
|
||||
"type": "bool_prefix",
|
||||
"fields": [
|
||||
"title",
|
||||
"title._2gram",
|
||||
"title._3gram"
|
||||
],
|
||||
"boost": 50
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,29 +19,3 @@ where
|
||||
and m.mod_deleted_at IS NULL
|
||||
order by m.title asc;
|
||||
|
||||
-- Top models within time period
|
||||
-- NB: id threshold is to avoid a full table scan
|
||||
select
|
||||
mw.token,
|
||||
mw.title,
|
||||
mw.weights_type,
|
||||
mw.weights_category,
|
||||
u.username as creator_username,
|
||||
r.use_count,
|
||||
mw.created_at,
|
||||
mw.user_deleted_at,
|
||||
mw.mod_deleted_at
|
||||
from (
|
||||
select maybe_model_token, count(*) as use_count
|
||||
from generic_inference_jobs
|
||||
where maybe_model_token IS NOT NULL
|
||||
and created_at > NOW() - INTERVAL 1 DAY
|
||||
and id > 40000000
|
||||
group by maybe_model_token
|
||||
) as r
|
||||
join model_weights as mw
|
||||
on mw.token = r.maybe_model_token
|
||||
join users as u
|
||||
on u.token = mw.creator_user_token
|
||||
order by r.use_count desc
|
||||
limit 100;
|
||||
|
||||
@@ -94,7 +94,6 @@ SET
|
||||
can_access_studio = false,
|
||||
maybe_feature_flags = 'studio,video_style_transfer'
|
||||
WHERE username IN (
|
||||
'FoxtailStudio',
|
||||
'chechisauri0',
|
||||
'dakrid',
|
||||
'omega7321',
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
select *
|
||||
from generic_inference_jobs
|
||||
where job_type = 'comfy_ui'
|
||||
and status NOT IN (
|
||||
'pending',
|
||||
'started',
|
||||
'complete_success'
|
||||
)
|
||||
order by id desc
|
||||
limit 5\G
|
||||
|
||||
-- List started jobs
|
||||
select *
|
||||
from generic_inference_jobs
|
||||
where job_type = 'comfy_ui'
|
||||
and status IN ('started')
|
||||
order by id desc
|
||||
limit 50\G
|
||||
|
||||
update generic_inference_jobs
|
||||
set inference_category = 'convert_bvh_to_workflow'
|
||||
where inference_category = 'deprecated_field'
|
||||
limit 5;
|
||||
|
||||
[2024-07-16T22:53:07Z ERROR inference_job::job::job_loop::main_loop] Error querying jobs: error: ""
|
||||
@@ -6,8 +6,3 @@
|
||||
select username from users where maybe_feature_flags like '%studio%';
|
||||
|
||||
select username from users where can_access_studio = true;
|
||||
|
||||
-- Who signed up recently and has access?
|
||||
select username, maybe_source
|
||||
from users where can_access_studio = true
|
||||
and created_at > NOW() - interval 20 minute;
|
||||
|
||||
@@ -11,72 +11,8 @@ from media_files as m
|
||||
join users as u
|
||||
on m.maybe_creator_user_token = u.token
|
||||
where u.can_access_studio = true
|
||||
and m.created_at > (CURDATE() - INTERVAL 14 DAY)
|
||||
and m.created_at > (CURDATE() - INTERVAL 1 WEEK)
|
||||
and m.is_intermediate_system_file = false
|
||||
and m.media_class = 'video'
|
||||
group by u.token
|
||||
order by video_count desc;
|
||||
|
||||
-- Without internal users
|
||||
select
|
||||
u.username,
|
||||
count(*) as video_count,
|
||||
u.maybe_source,
|
||||
u.created_at
|
||||
from media_files as m
|
||||
join users as u
|
||||
on m.maybe_creator_user_token = u.token
|
||||
where u.maybe_feature_flags LIKE '%studio%'
|
||||
and m.created_at > (CURDATE() - INTERVAL 1 DAY)
|
||||
and m.is_intermediate_system_file = false
|
||||
and m.media_class = 'video'
|
||||
and u.username NOT IN (
|
||||
'bflat',
|
||||
'candyfoxxx',
|
||||
'crossproduct1',
|
||||
'echelon',
|
||||
'endtimes',
|
||||
'heart_ribbon',
|
||||
'kasisnu',
|
||||
'mechacosm',
|
||||
'moonchamp',
|
||||
'olivicmic',
|
||||
'printrman',
|
||||
'vegito1089',
|
||||
'wilwong',
|
||||
'yae_ph'
|
||||
)
|
||||
group by u.token
|
||||
order by created_at desc;
|
||||
|
||||
-- See videos generated
|
||||
-- and m.is_intermediate_system_file IS TRUE
|
||||
-- where u.maybe_feature_flags LIKE '%studio%'
|
||||
select
|
||||
u.username,
|
||||
u.maybe_source,
|
||||
m.token,
|
||||
m.is_intermediate_system_file as sys_file,
|
||||
m.created_at
|
||||
from media_files as m
|
||||
join users as u
|
||||
on m.maybe_creator_user_token = u.token
|
||||
WHERE m.created_at > (CURDATE() - INTERVAL 1 DAY)
|
||||
and m.media_class = 'video'
|
||||
and u.username NOT IN (
|
||||
'bflat',
|
||||
'candyfoxxx',
|
||||
'crossproduct1',
|
||||
'echelon',
|
||||
'endtimes',
|
||||
'heart_ribbon',
|
||||
'kasisnu',
|
||||
'mechacosm',
|
||||
'moonchamp',
|
||||
'olivicmic',
|
||||
'printrman',
|
||||
'vegito1089',
|
||||
'wilwong',
|
||||
'yae_ph'
|
||||
)
|
||||
order by m.created_at desc;
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
-- noinspection SqlDialectInspectionForFile
|
||||
-- noinspection SqlNoDataSourceInspectionForFile
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
-- Enroll internal accounts in studio + loyalty features
|
||||
UPDATE users
|
||||
SET
|
||||
can_access_studio = true,
|
||||
maybe_feature_flags = 'explore_media,studio,video_style_transfer',
|
||||
maybe_loyalty_program_key = 'fakeyou_contributor',
|
||||
user_role_slug = "admin"
|
||||
WHERE username IN (
|
||||
'48hourfilm',
|
||||
'intro_video',
|
||||
'zzz_last_item'
|
||||
)
|
||||
LIMIT 5;
|
||||
@@ -199,7 +199,7 @@ CREATE TABLE generic_inference_jobs (
|
||||
attempt_count SMALLINT UNSIGNED NOT NULL DEFAULT 0,
|
||||
|
||||
-- If the user chooses to no longer display or poll the job, we mark this flag true.
|
||||
-- This should only be set for terminal state (completed or failed) jobs.
|
||||
-- This can only be set for terminal state (completed or failed) jobs.
|
||||
-- We use this flag to remove the job from the user's view.
|
||||
is_dismissed_by_user BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
|
||||
|
||||
@@ -6,12 +6,6 @@
|
||||
-- noinspection SqlResolveForFile
|
||||
|
||||
-- This table contains both user uploads and inference or processing results.
|
||||
--
|
||||
-- The fields in media_files that should be filterable are:
|
||||
-- * media_class ("audio", "video", "image", "dimensional")
|
||||
-- * media_type ("fbx", "glb", "scene_json", "png", "jpg", etc.)
|
||||
-- * engine_category ("scene", "character", "animation", "object", "image_plane", etc.)
|
||||
--
|
||||
CREATE TABLE media_files (
|
||||
-- Not used for anything except replication.
|
||||
id BIGINT(20) NOT NULL AUTO_INCREMENT,
|
||||
@@ -115,11 +109,6 @@ CREATE TABLE media_files (
|
||||
-- * `glb` for GLB files
|
||||
-- * `gltf` for GLTF files
|
||||
-- * `scene_ron` for SCN.RON files
|
||||
-- * `scene_json` for scene files for three.js
|
||||
-- * `pmd`
|
||||
-- * `vmd`
|
||||
-- * `pmx`
|
||||
-- * `csv`
|
||||
media_type VARCHAR(16) NOT NULL,
|
||||
|
||||
-- Broad class of media:
|
||||
@@ -128,15 +117,16 @@ CREATE TABLE media_files (
|
||||
-- * 'audio' for wav, mp3, etc.
|
||||
-- * 'image' for a variety of video types.
|
||||
-- * 'video' for a variety of video types.
|
||||
-- * 'dimensional' for a variety of 3d types
|
||||
-- * 'animation' for animations (engine)
|
||||
-- * 'character' for characters (engine)
|
||||
-- * 'prop' for props (engine)
|
||||
-- * 'scene' for scenes (engine; internal and external scenes)
|
||||
media_class VARCHAR(16) NOT NULL DEFAULT "unknown",
|
||||
|
||||
-- A media file's possible subtype. Typically used for Storyteller Studio.
|
||||
-- * 'mixamo' for mixamo animations (eg. for BVH, GLB, FBX, etc. files)
|
||||
-- * 'mocap_net' for mocapnet animations (eg. for BVH files)
|
||||
-- * 'scene'
|
||||
-- * 'character'
|
||||
-- * 'animation'
|
||||
-- * 'scene' for generic scenes (eg. for BVH, GLB, FBX, etc. files)
|
||||
maybe_media_subtype VARCHAR(32) DEFAULT NULL,
|
||||
|
||||
-- The file's mime type.
|
||||
|
||||
+21
-26
@@ -1,34 +1,29 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="description" content="SwaggerUI" />
|
||||
<title>Storyteller API</title>
|
||||
<link rel="stylesheet" href="//unpkg.com/swagger-ui-dist@5.11.0/swagger-ui.css" />
|
||||
</head>
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" type="text/css" href="//unpkg.com/swagger-ui-dist@3/swagger-ui.css">
|
||||
|
||||
<title>Storyteller API</title>
|
||||
|
||||
<body>
|
||||
<div id="app-docs" />
|
||||
|
||||
<div id="swagger-ui"></div>
|
||||
<script src="//unpkg.com/swagger-ui-dist@3/swagger-ui-bundle.js"></script>
|
||||
<script>
|
||||
|
||||
<script src="//unpkg.com/swagger-ui-dist@5.11.0/swagger-ui-bundle.js" crossorigin></script>
|
||||
<script src="//unpkg.com/swagger-ui-dist@5.11.0/swagger-ui-standalone-preset.js" crossorigin></script>
|
||||
<script>
|
||||
window.onload = () => {
|
||||
window.ui = SwaggerUIBundle({
|
||||
url: 'api.json',
|
||||
dom_id: '#swagger-ui',
|
||||
window.onload = function () {
|
||||
const ui = SwaggerUIBundle({
|
||||
url: "api.json",
|
||||
dom_id: "#app-docs",
|
||||
deepLinking: true,
|
||||
presets: [
|
||||
SwaggerUIBundle.presets.apis,
|
||||
SwaggerUIStandalonePreset
|
||||
],
|
||||
layout: "StandaloneLayout",
|
||||
tagsSorter: 'alpha', // Sort tags (endpoint groupings) alphabetically
|
||||
defaultModelRendering: 'model', // Show model instead of "example request"
|
||||
defaultModelExpandDepth: 6,
|
||||
});
|
||||
};
|
||||
</script>
|
||||
})
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
@@ -34,8 +34,8 @@ utoipa = { version = "4", features = ["chrono","actix_extras"] }
|
||||
[dev-dependencies]
|
||||
|
||||
# Enum utilities
|
||||
strum = { version = "0.26", features = ["derive"] }
|
||||
strum = { version = "0.25", features = ["derive"] }
|
||||
|
||||
# Test serialization
|
||||
serde_json = "1.0.108"
|
||||
toml = "0.8.14"
|
||||
toml = "0.5.8"
|
||||
|
||||
@@ -16,50 +16,32 @@ use utoipa::ToSchema;
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize, Default, ToSchema)]
|
||||
pub enum InferenceCategory {
|
||||
/// Deprecate this field !!!
|
||||
/// We should drain all jobs from using this database field, then remove it.
|
||||
#[serde(rename = "deprecated_field")]
|
||||
DeprecatedField,
|
||||
|
||||
/// Facial lipsync animation (eg. SadTalker, Wav2Lip)
|
||||
/// Eg. SadTalker and possibly Wav2Lip
|
||||
#[serde(rename = "lipsync_animation")]
|
||||
#[default]
|
||||
LipsyncAnimation,
|
||||
|
||||
/// FakeYou's text to speech (eg. Tacotron2)
|
||||
#[serde(rename = "text_to_speech")]
|
||||
TextToSpeech,
|
||||
|
||||
/// FakeYou's voice conversion (eg. svc, rvc)
|
||||
#[serde(rename = "voice_conversion")]
|
||||
VoiceConversion,
|
||||
|
||||
/// Image generation (eg. Stable Diffusion 1.5)
|
||||
#[serde(rename = "image_generation")]
|
||||
ImageGeneration,
|
||||
|
||||
/// Turn video into animation data with mocap processing (eg. Mocapnet).
|
||||
#[serde(rename = "mocap")]
|
||||
Mocap,
|
||||
|
||||
/// ComfyUI workflows
|
||||
/// This is what powers Storyteller Studio!
|
||||
#[serde(rename = "workflow")]
|
||||
Workflow,
|
||||
|
||||
/// FBX to GLTF/GLB.
|
||||
/// Still supported, but few people will use it.
|
||||
#[serde(rename = "format_conversion")]
|
||||
FormatConversion,
|
||||
|
||||
/// DEPRECATED. Do not use.
|
||||
/// This was for ReRenderAVideo, which we never productionized.
|
||||
#[deprecated(note = "This was for ReRenderAVideo, which we never productionized.")]
|
||||
#[serde(rename = "video_filter")]
|
||||
VideoFilter,
|
||||
|
||||
/// DEPRECATED. Bevy engine serverside rendering.
|
||||
#[deprecated(note = "This was for Bevy engine's server side rendering.")]
|
||||
#[serde(rename = "image_generation")]
|
||||
ImageGeneration,
|
||||
|
||||
#[serde(rename = "mocap")]
|
||||
Mocap,
|
||||
|
||||
#[serde(rename = "workflow")]
|
||||
Workflow,
|
||||
|
||||
#[serde(rename = "format_conversion")]
|
||||
FormatConversion,
|
||||
|
||||
#[serde(rename = "convert_bvh_to_workflow")]
|
||||
ConvertBvhToWorkflow,
|
||||
}
|
||||
@@ -73,30 +55,28 @@ impl_mysql_from_row!(InferenceCategory);
|
||||
impl InferenceCategory {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::DeprecatedField => "deprecated_field",
|
||||
Self::LipsyncAnimation => "lipsync_animation",
|
||||
Self::TextToSpeech => "text_to_speech",
|
||||
Self::VoiceConversion => "voice_conversion",
|
||||
Self::VideoFilter => "video_filter",
|
||||
Self::ImageGeneration => "image_generation",
|
||||
Self::Mocap => "mocap",
|
||||
Self::Workflow => "workflow",
|
||||
Self::FormatConversion => "format_conversion",
|
||||
Self::VideoFilter => "video_filter",
|
||||
Self::ConvertBvhToWorkflow => "convert_bvh_to_workflow",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"deprecated_field" => Ok(Self::DeprecatedField),
|
||||
"lipsync_animation" => Ok(Self::LipsyncAnimation),
|
||||
"text_to_speech" => Ok(Self::TextToSpeech),
|
||||
"voice_conversion" => Ok(Self::VoiceConversion),
|
||||
"video_filter" => Ok(Self::VideoFilter),
|
||||
"image_generation" => Ok(Self::ImageGeneration),
|
||||
"mocap" => Ok(Self::Mocap),
|
||||
"workflow" => Ok(Self::Workflow),
|
||||
"format_conversion" => Ok(Self::FormatConversion),
|
||||
"video_filter" => Ok(Self::VideoFilter),
|
||||
"convert_bvh_to_workflow" => Ok(Self::ConvertBvhToWorkflow),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
@@ -106,15 +86,14 @@ impl InferenceCategory {
|
||||
// NB: BTreeSet is sorted
|
||||
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
|
||||
BTreeSet::from([
|
||||
Self::DeprecatedField,
|
||||
Self::LipsyncAnimation,
|
||||
Self::TextToSpeech,
|
||||
Self::VoiceConversion,
|
||||
Self::VideoFilter,
|
||||
Self::ImageGeneration,
|
||||
Self::Mocap,
|
||||
Self::Workflow,
|
||||
Self::FormatConversion,
|
||||
Self::VideoFilter,
|
||||
Self::ConvertBvhToWorkflow,
|
||||
])
|
||||
}
|
||||
@@ -130,43 +109,40 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(InferenceCategory::DeprecatedField, "deprecated_field");
|
||||
assert_serialization(InferenceCategory::LipsyncAnimation, "lipsync_animation");
|
||||
assert_serialization(InferenceCategory::TextToSpeech, "text_to_speech");
|
||||
assert_serialization(InferenceCategory::VoiceConversion, "voice_conversion");
|
||||
assert_serialization(InferenceCategory::VideoFilter, "video_filter");
|
||||
assert_serialization(InferenceCategory::ImageGeneration, "image_generation");
|
||||
assert_serialization(InferenceCategory::Mocap, "mocap");
|
||||
assert_serialization(InferenceCategory::Workflow, "workflow");
|
||||
assert_serialization(InferenceCategory::FormatConversion, "format_conversion");
|
||||
assert_serialization(InferenceCategory::VideoFilter, "video_filter");
|
||||
assert_serialization(InferenceCategory::ConvertBvhToWorkflow, "convert_bvh_to_workflow");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_str() {
|
||||
assert_eq!(InferenceCategory::DeprecatedField.to_str(), "deprecated_field");
|
||||
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::VideoFilter.to_str(), "video_filter");
|
||||
assert_eq!(InferenceCategory::ImageGeneration.to_str(), "image_generation");
|
||||
assert_eq!(InferenceCategory::Mocap.to_str(), "mocap");
|
||||
assert_eq!(InferenceCategory::Workflow.to_str(), "workflow");
|
||||
assert_eq!(InferenceCategory::FormatConversion.to_str(), "format_conversion");
|
||||
assert_eq!(InferenceCategory::VideoFilter.to_str(), "video_filter");
|
||||
assert_eq!(InferenceCategory::ConvertBvhToWorkflow.to_str(), "convert_bvh_to_workflow");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_str() {
|
||||
assert_eq!(InferenceCategory::from_str("deprecated_field").unwrap(), InferenceCategory::DeprecatedField);
|
||||
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("video_filter").unwrap(), InferenceCategory::VideoFilter);
|
||||
assert_eq!(InferenceCategory::from_str("image_generation").unwrap(), InferenceCategory::ImageGeneration);
|
||||
assert_eq!(InferenceCategory::from_str("mocap").unwrap(), InferenceCategory::Mocap);
|
||||
assert_eq!(InferenceCategory::from_str("workflow").unwrap(), InferenceCategory::Workflow);
|
||||
assert_eq!(InferenceCategory::from_str("format_conversion").unwrap(), InferenceCategory::FormatConversion);
|
||||
assert_eq!(InferenceCategory::from_str("video_filter").unwrap(), InferenceCategory::VideoFilter);
|
||||
assert_eq!(InferenceCategory::from_str("convert_bvh_to_workflow").unwrap(), InferenceCategory::ConvertBvhToWorkflow);
|
||||
}
|
||||
|
||||
@@ -174,16 +150,15 @@ mod tests {
|
||||
fn all_variants() {
|
||||
// Static check
|
||||
let mut variants = InferenceCategory::all_variants();
|
||||
assert_eq!(variants.len(), 10);
|
||||
assert_eq!(variants.pop_first(), Some(InferenceCategory::DeprecatedField));
|
||||
assert_eq!(variants.len(), 9);
|
||||
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::VideoFilter));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceCategory::ImageGeneration));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceCategory::Mocap));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceCategory::Workflow));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceCategory::FormatConversion));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceCategory::VideoFilter));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceCategory::ConvertBvhToWorkflow));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
|
||||
|
||||
@@ -15,21 +15,11 @@ use strum::EnumIter;
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize, Default)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum InferenceJobType {
|
||||
/// Storyteller Studio and Video Style Transfer Jobs (which we may want to split).
|
||||
/// These run in Comfy.
|
||||
/// TODO(bt,2024-07-15): We may segregate these two job types in the future
|
||||
VideoRender,
|
||||
|
||||
/// Live Portrait Jobs.
|
||||
/// These run in Comfy.
|
||||
LivePortrait,
|
||||
|
||||
/// Voice jobs that use GPT-Sovits
|
||||
GptSovits,
|
||||
/// Job that converts bevy to workflow files
|
||||
#[serde(rename = "bevy_to_workflow")]
|
||||
BevyToWorkflow,
|
||||
|
||||
/// Jobs that run ComfyUI workflows
|
||||
/// This is actually just for Video Style Transfer and Storyteller Studio.
|
||||
#[deprecated(note = "Use VideoRender instead.")]
|
||||
ComfyUi,
|
||||
|
||||
/// A job that turns "FBX" game engine files into "GLTF" files (Bevy-compatible).
|
||||
@@ -39,6 +29,10 @@ pub enum InferenceJobType {
|
||||
/// Process a video into BVH mocap animation data for game engines
|
||||
MocapNet,
|
||||
|
||||
/// Re-render a video is a video style transfer algorithm. We developed code
|
||||
/// around it, but chose to develop AnimateDiff / ComfyUI support instead.
|
||||
RerenderAVideo,
|
||||
|
||||
/// RVC is a voice conversion model. RVCv2 is the most popular such model currently.
|
||||
#[serde(rename = "rvc_v2")]
|
||||
RvcV2,
|
||||
@@ -64,18 +58,6 @@ pub enum InferenceJobType {
|
||||
/// (i.e. when we backfill the database column and make it non-nullable)
|
||||
#[default]
|
||||
Unknown,
|
||||
|
||||
/// DEPRECATED. DO NOT USE.
|
||||
/// Job that converts bevy to workflow files
|
||||
#[deprecated(note = "This was for Bevy engine's server side rendering.")]
|
||||
#[serde(rename = "bevy_to_workflow")]
|
||||
BevyToWorkflow,
|
||||
|
||||
#[deprecated(note = "This was for ReRenderAVideo, which we never productionized.")]
|
||||
/// DEPRECATED. DO NOT USE.
|
||||
/// Re-render a video is a video style transfer algorithm. We developed code
|
||||
/// around it, but chose to develop AnimateDiff / ComfyUI support instead.
|
||||
RerenderAVideo,
|
||||
}
|
||||
|
||||
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
|
||||
@@ -86,12 +68,11 @@ impl_mysql_enum_coders!(InferenceJobType);
|
||||
impl InferenceJobType {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::VideoRender => "video_render",
|
||||
Self::LivePortrait => "live_portrait",
|
||||
Self::GptSovits => "gpt_sovits",
|
||||
Self::BevyToWorkflow => "bevy_to_workflow",
|
||||
Self::ComfyUi => "comfy_ui",
|
||||
Self::ConvertFbxToGltf => "convert_fbx_gltf",
|
||||
Self::MocapNet => "mocap_net",
|
||||
Self::RerenderAVideo => "rerender_a_video",
|
||||
Self::RvcV2 => "rvc_v2",
|
||||
Self::SadTalker => "sad_talker",
|
||||
Self::SoVitsSvc => "so_vits_svc",
|
||||
@@ -99,19 +80,16 @@ impl InferenceJobType {
|
||||
Self::StyleTTS2 => "styletts2",
|
||||
Self::Tacotron2 => "tacotron2",
|
||||
Self::Unknown => "unknown",
|
||||
Self::BevyToWorkflow => "bevy_to_workflow",
|
||||
Self::RerenderAVideo => "rerender_a_video",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"video_render" => Ok(Self::VideoRender),
|
||||
"live_portrait" => Ok(Self::LivePortrait),
|
||||
"gpt_sovits" => Ok(Self::GptSovits),
|
||||
"bevy_to_workflow" => Ok(Self::BevyToWorkflow),
|
||||
"comfy_ui" => Ok(Self::ComfyUi),
|
||||
"convert_fbx_gltf" => Ok(Self::ConvertFbxToGltf),
|
||||
"mocap_net" => Ok(Self::MocapNet),
|
||||
"rerender_a_video" => Ok(Self::RerenderAVideo),
|
||||
"rvc_v2" => Ok(Self::RvcV2),
|
||||
"sad_talker" => Ok(Self::SadTalker),
|
||||
"so_vits_svc" => Ok(Self::SoVitsSvc),
|
||||
@@ -119,8 +97,6 @@ impl InferenceJobType {
|
||||
"styletts2" => Ok(Self::StyleTTS2),
|
||||
"tacotron2" => Ok(Self::Tacotron2),
|
||||
"unknown" => Ok(Self::Unknown),
|
||||
"bevy_to_workflow" => Ok(Self::BevyToWorkflow),
|
||||
"rerender_a_video" => Ok(Self::RerenderAVideo),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
@@ -129,12 +105,11 @@ impl InferenceJobType {
|
||||
// NB: BTreeSet is sorted
|
||||
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
|
||||
BTreeSet::from([
|
||||
Self::VideoRender,
|
||||
Self::LivePortrait,
|
||||
Self::GptSovits,
|
||||
Self::BevyToWorkflow,
|
||||
Self::ComfyUi,
|
||||
Self::ConvertFbxToGltf,
|
||||
Self::MocapNet,
|
||||
Self::RerenderAVideo,
|
||||
Self::RvcV2,
|
||||
Self::SadTalker,
|
||||
Self::SoVitsSvc,
|
||||
@@ -142,8 +117,6 @@ impl InferenceJobType {
|
||||
Self::StyleTTS2,
|
||||
Self::Tacotron2,
|
||||
Self::Unknown,
|
||||
Self::BevyToWorkflow,
|
||||
Self::RerenderAVideo,
|
||||
])
|
||||
}
|
||||
}
|
||||
@@ -163,12 +136,11 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(InferenceJobType::VideoRender, "video_render");
|
||||
assert_serialization(InferenceJobType::LivePortrait, "live_portrait");
|
||||
assert_serialization(InferenceJobType::GptSovits, "gpt_sovits");
|
||||
assert_serialization(InferenceJobType::BevyToWorkflow, "bevy_to_workflow");
|
||||
assert_serialization(InferenceJobType::ComfyUi, "comfy_ui");
|
||||
assert_serialization(InferenceJobType::ConvertFbxToGltf, "convert_fbx_gltf");
|
||||
assert_serialization(InferenceJobType::MocapNet, "mocap_net");
|
||||
assert_serialization(InferenceJobType::RerenderAVideo, "rerender_a_video");
|
||||
assert_serialization(InferenceJobType::RvcV2, "rvc_v2");
|
||||
assert_serialization(InferenceJobType::SadTalker, "sad_talker");
|
||||
assert_serialization(InferenceJobType::SoVitsSvc, "so_vits_svc");
|
||||
@@ -176,18 +148,15 @@ mod tests {
|
||||
assert_serialization(InferenceJobType::StyleTTS2, "styletts2");
|
||||
assert_serialization(InferenceJobType::Tacotron2, "tacotron2");
|
||||
assert_serialization(InferenceJobType::Unknown, "unknown");
|
||||
assert_serialization(InferenceJobType::BevyToWorkflow, "bevy_to_workflow");
|
||||
assert_serialization(InferenceJobType::RerenderAVideo, "rerender_a_video");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_str() {
|
||||
assert_eq!(InferenceJobType::VideoRender.to_str(), "video_render");
|
||||
assert_eq!(InferenceJobType::LivePortrait.to_str(), "live_portrait");
|
||||
assert_eq!(InferenceJobType::GptSovits.to_str(), "gpt_sovits");
|
||||
assert_eq!(InferenceJobType::BevyToWorkflow.to_str(), "bevy_to_workflow");
|
||||
assert_eq!(InferenceJobType::ComfyUi.to_str(), "comfy_ui");
|
||||
assert_eq!(InferenceJobType::ConvertFbxToGltf.to_str(), "convert_fbx_gltf");
|
||||
assert_eq!(InferenceJobType::MocapNet.to_str(), "mocap_net");
|
||||
assert_eq!(InferenceJobType::RerenderAVideo.to_str(), "rerender_a_video");
|
||||
assert_eq!(InferenceJobType::RvcV2.to_str(), "rvc_v2");
|
||||
assert_eq!(InferenceJobType::SadTalker.to_str(), "sad_talker");
|
||||
assert_eq!(InferenceJobType::SoVitsSvc.to_str(), "so_vits_svc");
|
||||
@@ -195,18 +164,15 @@ mod tests {
|
||||
assert_eq!(InferenceJobType::StyleTTS2.to_str(), "styletts2");
|
||||
assert_eq!(InferenceJobType::Tacotron2.to_str(), "tacotron2");
|
||||
assert_eq!(InferenceJobType::Unknown.to_str(), "unknown");
|
||||
assert_eq!(InferenceJobType::BevyToWorkflow.to_str(), "bevy_to_workflow");
|
||||
assert_eq!(InferenceJobType::RerenderAVideo.to_str(), "rerender_a_video");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_str() {
|
||||
assert_eq!(InferenceJobType::from_str("video_render").unwrap(), InferenceJobType::VideoRender);
|
||||
assert_eq!(InferenceJobType::from_str("live_portrait").unwrap(), InferenceJobType::LivePortrait);
|
||||
assert_eq!(InferenceJobType::from_str("gpt_sovits").unwrap(), InferenceJobType::GptSovits);
|
||||
assert_eq!(InferenceJobType::from_str("bevy_to_workflow").unwrap(), InferenceJobType::BevyToWorkflow);
|
||||
assert_eq!(InferenceJobType::from_str("comfy_ui").unwrap(), InferenceJobType::ComfyUi);
|
||||
assert_eq!(InferenceJobType::from_str("convert_fbx_gltf").unwrap(), InferenceJobType::ConvertFbxToGltf);
|
||||
assert_eq!(InferenceJobType::from_str("mocap_net").unwrap(), InferenceJobType::MocapNet);
|
||||
assert_eq!(InferenceJobType::from_str("rerender_a_video").unwrap(), InferenceJobType::RerenderAVideo);
|
||||
assert_eq!(InferenceJobType::from_str("rvc_v2").unwrap(), InferenceJobType::RvcV2);
|
||||
assert_eq!(InferenceJobType::from_str("sad_talker").unwrap(), InferenceJobType::SadTalker);
|
||||
assert_eq!(InferenceJobType::from_str("so_vits_svc").unwrap(), InferenceJobType::SoVitsSvc);
|
||||
@@ -214,21 +180,18 @@ mod tests {
|
||||
assert_eq!(InferenceJobType::from_str("styletts2").unwrap(), InferenceJobType::StyleTTS2);
|
||||
assert_eq!(InferenceJobType::from_str("tacotron2").unwrap(), InferenceJobType::Tacotron2);
|
||||
assert_eq!(InferenceJobType::from_str("unknown").unwrap(), InferenceJobType::Unknown);
|
||||
assert_eq!(InferenceJobType::from_str("bevy_to_workflow").unwrap(), InferenceJobType::BevyToWorkflow);
|
||||
assert_eq!(InferenceJobType::from_str("rerender_a_video").unwrap(), InferenceJobType::RerenderAVideo);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
// Static check
|
||||
let mut variants = InferenceJobType::all_variants();
|
||||
assert_eq!(variants.len(), 15);
|
||||
assert_eq!(variants.pop_first(), Some(InferenceJobType::VideoRender));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceJobType::LivePortrait));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceJobType::GptSovits));
|
||||
assert_eq!(variants.len(), 12);
|
||||
assert_eq!(variants.pop_first(), Some(InferenceJobType::BevyToWorkflow));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceJobType::ComfyUi));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceJobType::ConvertFbxToGltf));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceJobType::MocapNet));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceJobType::RerenderAVideo));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceJobType::RvcV2));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceJobType::SadTalker));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceJobType::SoVitsSvc));
|
||||
@@ -236,8 +199,6 @@ mod tests {
|
||||
assert_eq!(variants.pop_first(), Some(InferenceJobType::StyleTTS2));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceJobType::Tacotron2));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceJobType::Unknown));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceJobType::BevyToWorkflow));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceJobType::RerenderAVideo));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
|
||||
// Generated check
|
||||
|
||||
@@ -17,10 +17,6 @@ use strum::EnumIter;
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)]
|
||||
pub enum InferenceModelType {
|
||||
// TODO(bt,2024-07-15): This is too generic. We probably need "StorytellerStudio", "LivePortrait", etc.
|
||||
#[serde(rename = "comfy_ui")]
|
||||
ComfyUi,
|
||||
|
||||
#[serde(rename = "rvc_v2")]
|
||||
RvcV2,
|
||||
// NB: sad_talker does use user-supplied models, so there is no "model token"
|
||||
@@ -41,6 +37,8 @@ pub enum InferenceModelType {
|
||||
StableDiffusion,
|
||||
#[serde(rename = "mocap_net")]
|
||||
MocapNet,
|
||||
#[serde(rename = "comfy_ui")]
|
||||
ComfyUi,
|
||||
#[serde(rename = "styletts2")]
|
||||
StyleTTS2,
|
||||
/// A job that turns "FBX" game engine files into "GLTF" files (Bevy-compatible).
|
||||
|
||||
@@ -21,39 +21,17 @@ pub enum MediaFileEngineCategory {
|
||||
/// A 3D character model.
|
||||
Character,
|
||||
|
||||
/// A 3D non-humanoid model, e.g. dragon, wolf, slime creature, etc.
|
||||
/// These may or may not have a skeleton that can be animated with IK/FK.
|
||||
Creature,
|
||||
|
||||
/// A 3D skeletal animation sequence that can be applied to a character,
|
||||
/// creature, etc. Typically, these use Mixamo or Move.ai.
|
||||
/// A 3D animation.
|
||||
Animation,
|
||||
|
||||
/// A facial blend shape / shape key animation. Currently, these
|
||||
/// are 100% ARKit.
|
||||
/// A facial blend shape / shape key animation.
|
||||
Expression,
|
||||
|
||||
/// A large 3D object that can be used as a backdrop for a scene,
|
||||
/// a.k.a. "set", "stage", etc. These are typically self-contained
|
||||
/// locations, buildings, or environments.
|
||||
Location,
|
||||
|
||||
/// All items used to add atmosphere to a scene, e.g. furniture, plants,
|
||||
/// vehicles, radios, and certain props. (We'll reserve the word props for
|
||||
/// "hand props" later.)
|
||||
SetDressing,
|
||||
|
||||
/// A 3D object that doesn't fit with the other types.
|
||||
Object,
|
||||
|
||||
/// A 3D skybox.
|
||||
Skybox,
|
||||
|
||||
/// An Image Plane (texture that spawns as an object)
|
||||
ImagePlane,
|
||||
|
||||
/// A Video Plane (texture that spawns as an object)
|
||||
VideoPlane,
|
||||
}
|
||||
|
||||
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
|
||||
@@ -67,15 +45,10 @@ impl MediaFileEngineCategory {
|
||||
match self {
|
||||
Self::Scene => "scene",
|
||||
Self::Character => "character",
|
||||
Self::Creature => "creature",
|
||||
Self::Animation => "animation",
|
||||
Self::Expression => "expression",
|
||||
Self::Location => "location",
|
||||
Self::SetDressing => "set_dressing",
|
||||
Self::Object => "object",
|
||||
Self::Skybox => "skybox",
|
||||
Self::ImagePlane => "image_plane",
|
||||
Self::VideoPlane => "video_plane",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,15 +56,10 @@ impl MediaFileEngineCategory {
|
||||
match value {
|
||||
"scene" => Ok(Self::Scene),
|
||||
"character" => Ok(Self::Character),
|
||||
"creature" => Ok(Self::Creature),
|
||||
"animation" => Ok(Self::Animation),
|
||||
"expression" => Ok(Self::Expression),
|
||||
"location" => Ok(Self::Location),
|
||||
"set_dressing" => Ok(Self::SetDressing),
|
||||
"object" => Ok(Self::Object),
|
||||
"skybox" => Ok(Self::Skybox),
|
||||
"image_plane" => Ok(Self::ImagePlane),
|
||||
"video_plane" => Ok(Self::VideoPlane),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
@@ -102,15 +70,10 @@ impl MediaFileEngineCategory {
|
||||
BTreeSet::from([
|
||||
Self::Scene,
|
||||
Self::Character,
|
||||
Self::Creature,
|
||||
Self::Animation,
|
||||
Self::Expression,
|
||||
Self::Location,
|
||||
Self::SetDressing,
|
||||
Self::Object,
|
||||
Self::Skybox,
|
||||
Self::ImagePlane,
|
||||
Self::VideoPlane,
|
||||
])
|
||||
}
|
||||
}
|
||||
@@ -127,63 +90,43 @@ mod tests {
|
||||
fn test_serialization() {
|
||||
assert_serialization(MediaFileEngineCategory::Scene, "scene");
|
||||
assert_serialization(MediaFileEngineCategory::Character, "character");
|
||||
assert_serialization(MediaFileEngineCategory::Creature, "creature");
|
||||
assert_serialization(MediaFileEngineCategory::Animation, "animation");
|
||||
assert_serialization(MediaFileEngineCategory::Expression, "expression");
|
||||
assert_serialization(MediaFileEngineCategory::Location, "location");
|
||||
assert_serialization(MediaFileEngineCategory::SetDressing, "set_dressing");
|
||||
assert_serialization(MediaFileEngineCategory::Object, "object");
|
||||
assert_serialization(MediaFileEngineCategory::Skybox, "skybox");
|
||||
assert_serialization(MediaFileEngineCategory::ImagePlane, "image_plane");
|
||||
assert_serialization(MediaFileEngineCategory::VideoPlane, "video_plane");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_str() {
|
||||
assert_eq!(MediaFileEngineCategory::Scene.to_str(), "scene");
|
||||
assert_eq!(MediaFileEngineCategory::Character.to_str(), "character");
|
||||
assert_eq!(MediaFileEngineCategory::Creature.to_str(), "creature");
|
||||
assert_eq!(MediaFileEngineCategory::Animation.to_str(), "animation");
|
||||
assert_eq!(MediaFileEngineCategory::Expression.to_str(), "expression");
|
||||
assert_eq!(MediaFileEngineCategory::Location.to_str(), "location");
|
||||
assert_eq!(MediaFileEngineCategory::SetDressing.to_str(), "set_dressing");
|
||||
assert_eq!(MediaFileEngineCategory::Object.to_str(), "object");
|
||||
assert_eq!(MediaFileEngineCategory::Skybox.to_str(), "skybox");
|
||||
assert_eq!(MediaFileEngineCategory::ImagePlane.to_str(), "image_plane");
|
||||
assert_eq!(MediaFileEngineCategory::VideoPlane.to_str(), "video_plane");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_str() {
|
||||
assert_eq!(MediaFileEngineCategory::from_str("scene").unwrap(), MediaFileEngineCategory::Scene);
|
||||
assert_eq!(MediaFileEngineCategory::from_str("character").unwrap(), MediaFileEngineCategory::Character);
|
||||
assert_eq!(MediaFileEngineCategory::from_str("creature").unwrap(), MediaFileEngineCategory::Creature);
|
||||
assert_eq!(MediaFileEngineCategory::from_str("animation").unwrap(), MediaFileEngineCategory::Animation);
|
||||
assert_eq!(MediaFileEngineCategory::from_str("expression").unwrap(), MediaFileEngineCategory::Expression);
|
||||
assert_eq!(MediaFileEngineCategory::from_str("location").unwrap(), MediaFileEngineCategory::Location);
|
||||
assert_eq!(MediaFileEngineCategory::from_str("set_dressing").unwrap(), MediaFileEngineCategory::SetDressing);
|
||||
assert_eq!(MediaFileEngineCategory::from_str("object").unwrap(), MediaFileEngineCategory::Object);
|
||||
assert_eq!(MediaFileEngineCategory::from_str("skybox").unwrap(), MediaFileEngineCategory::Skybox);
|
||||
assert_eq!(MediaFileEngineCategory::from_str("image_plane").unwrap(), MediaFileEngineCategory::ImagePlane);
|
||||
assert_eq!(MediaFileEngineCategory::from_str("video_plane").unwrap(), MediaFileEngineCategory::VideoPlane);
|
||||
assert!(MediaFileEngineCategory::from_str("foo").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
let mut variants = MediaFileEngineCategory::all_variants();
|
||||
assert_eq!(variants.len(), 11);
|
||||
assert_eq!(variants.len(), 6);
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileEngineCategory::Scene));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileEngineCategory::Character));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileEngineCategory::Creature));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileEngineCategory::Animation));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileEngineCategory::Expression));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileEngineCategory::Location));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileEngineCategory::SetDressing));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileEngineCategory::Object));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileEngineCategory::Skybox));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileEngineCategory::ImagePlane));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileEngineCategory::VideoPlane));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,9 +47,6 @@ pub enum MediaFileOriginModelType {
|
||||
|
||||
#[serde(rename = "stable_diffusion_1_5")]
|
||||
StableDiffusion15,
|
||||
|
||||
#[serde(rename = "gpt_sovits")]
|
||||
GptSovits,
|
||||
}
|
||||
|
||||
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
|
||||
@@ -70,8 +67,7 @@ impl MediaFileOriginModelType {
|
||||
Self::MocapNet => "mocap_net",
|
||||
Self::ComfyUi => "comfy_ui",
|
||||
Self::StyleTTS2 => "styletts2",
|
||||
Self::StableDiffusion15 => "stable_diffusion_1_5",
|
||||
Self::GptSovits => "gpt_sovits",
|
||||
Self::StableDiffusion15 => "stable_diffusion_1_5"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +83,6 @@ impl MediaFileOriginModelType {
|
||||
"comfy_ui" => Ok(Self::ComfyUi),
|
||||
"styletts2" => Ok(Self::StyleTTS2),
|
||||
"stable_diffusion_1_5" => Ok(Self::StableDiffusion15),
|
||||
"gpt_sovits" => Ok(Self::GptSovits),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
@@ -105,8 +100,7 @@ impl MediaFileOriginModelType {
|
||||
Self::MocapNet,
|
||||
Self::ComfyUi,
|
||||
Self::StyleTTS2,
|
||||
Self::StableDiffusion15,
|
||||
Self::GptSovits,
|
||||
Self::StableDiffusion15
|
||||
])
|
||||
}
|
||||
}
|
||||
@@ -136,7 +130,6 @@ mod tests {
|
||||
assert_eq!(MediaFileOriginModelType::ComfyUi.to_str(), "comfy_ui");
|
||||
assert_eq!(MediaFileOriginModelType::StyleTTS2.to_str(), "styletts2");
|
||||
assert_eq!(MediaFileOriginModelType::StableDiffusion15.to_str(), "stable_diffusion_1_5");
|
||||
assert_eq!(MediaFileOriginModelType::GptSovits.to_str(), "gpt_sovits");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -151,14 +144,13 @@ mod tests {
|
||||
assert_eq!(MediaFileOriginModelType::from_str("comfy_ui").unwrap(), MediaFileOriginModelType::ComfyUi);
|
||||
assert_eq!(MediaFileOriginModelType::from_str("styletts2").unwrap(), MediaFileOriginModelType::StyleTTS2);
|
||||
assert_eq!(MediaFileOriginModelType::from_str("stable_diffusion_1_5").unwrap(), MediaFileOriginModelType::StableDiffusion15);
|
||||
assert_eq!(MediaFileOriginModelType::from_str("gpt_sovits").unwrap(), MediaFileOriginModelType::GptSovits);
|
||||
assert!(MediaFileOriginModelType::from_str("foo").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
let mut variants = MediaFileOriginModelType::all_variants();
|
||||
assert_eq!(variants.len(), 11);
|
||||
assert_eq!(variants.len(), 10);
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginModelType::RvcV2));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginModelType::SadTalker));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginModelType::SoVitsSvc));
|
||||
@@ -169,7 +161,6 @@ mod tests {
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginModelType::ComfyUi));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginModelType::StyleTTS2));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginModelType::StableDiffusion15));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginModelType::GptSovits));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,17 +15,14 @@ use utoipa::ToSchema;
|
||||
pub enum MediaFileType {
|
||||
// TODO(bt): Deprecate and split into audio mime types; use media_class to represent broadly
|
||||
/// Audio files: wav, mp3, etc.
|
||||
#[deprecated]
|
||||
Audio,
|
||||
|
||||
// TODO(bt): Deprecate and split into image mime types; use media_class to represent broadly
|
||||
/// Image files: png, jpeg, etc.
|
||||
#[deprecated]
|
||||
Image,
|
||||
|
||||
// TODO(bt): Deprecate and split into video mime types; use media_class to represent broadly
|
||||
/// Video files: mp4, etc.
|
||||
#[deprecated]
|
||||
Video,
|
||||
|
||||
/// BVH files (for Bevy)
|
||||
@@ -64,18 +61,6 @@ pub enum MediaFileType {
|
||||
|
||||
/// CSV format. (We use these for ArKit)
|
||||
Csv,
|
||||
|
||||
/// Jpeg images
|
||||
Jpg,
|
||||
|
||||
/// Png images
|
||||
Png,
|
||||
|
||||
/// Gif images
|
||||
Gif,
|
||||
|
||||
/// Mp4 videos
|
||||
Mp4
|
||||
}
|
||||
|
||||
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
|
||||
@@ -100,10 +85,6 @@ impl MediaFileType {
|
||||
Self::Vmd => "vmd",
|
||||
Self::Pmx => "pmx",
|
||||
Self::Csv => "csv",
|
||||
Self::Jpg => "jpg",
|
||||
Self::Png => "png",
|
||||
Self::Gif => "gif",
|
||||
Self::Mp4 => "mp4",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,10 +103,6 @@ impl MediaFileType {
|
||||
"vmd" => Ok(Self::Vmd),
|
||||
"pmx" => Ok(Self::Pmx),
|
||||
"csv" => Ok(Self::Csv),
|
||||
"jpg" => Ok(Self::Jpg),
|
||||
"png" => Ok(Self::Png),
|
||||
"gif" => Ok(Self::Gif),
|
||||
"mp4" => Ok(Self::Mp4),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
@@ -147,10 +124,6 @@ impl MediaFileType {
|
||||
Self::Vmd,
|
||||
Self::Pmx,
|
||||
Self::Csv,
|
||||
Self::Jpg,
|
||||
Self::Png,
|
||||
Self::Gif,
|
||||
Self::Mp4,
|
||||
])
|
||||
}
|
||||
}
|
||||
@@ -178,10 +151,6 @@ mod tests {
|
||||
assert_serialization(MediaFileType::Vmd, "vmd");
|
||||
assert_serialization(MediaFileType::Pmx, "pmx");
|
||||
assert_serialization(MediaFileType::Csv, "csv");
|
||||
assert_serialization(MediaFileType::Jpg, "jpg");
|
||||
assert_serialization(MediaFileType::Png, "png");
|
||||
assert_serialization(MediaFileType::Gif, "gif");
|
||||
assert_serialization(MediaFileType::Mp4, "mp4");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -203,10 +172,6 @@ mod tests {
|
||||
assert_eq!(MediaFileType::Vmd.to_str(), "vmd");
|
||||
assert_eq!(MediaFileType::Pmx.to_str(), "pmx");
|
||||
assert_eq!(MediaFileType::Csv.to_str(), "csv");
|
||||
assert_eq!(MediaFileType::Jpg.to_str(), "jpg");
|
||||
assert_eq!(MediaFileType::Png.to_str(), "png");
|
||||
assert_eq!(MediaFileType::Gif.to_str(), "gif");
|
||||
assert_eq!(MediaFileType::Mp4.to_str(), "mp4");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -224,10 +189,6 @@ mod tests {
|
||||
assert_eq!(MediaFileType::from_str("vmd").unwrap(), MediaFileType::Vmd);
|
||||
assert_eq!(MediaFileType::from_str("pmx").unwrap(), MediaFileType::Pmx);
|
||||
assert_eq!(MediaFileType::from_str("csv").unwrap(), MediaFileType::Csv);
|
||||
assert_eq!(MediaFileType::from_str("jpg").unwrap(), MediaFileType::Jpg);
|
||||
assert_eq!(MediaFileType::from_str("png").unwrap(), MediaFileType::Png);
|
||||
assert_eq!(MediaFileType::from_str("gif").unwrap(), MediaFileType::Gif);
|
||||
assert_eq!(MediaFileType::from_str("mp4").unwrap(), MediaFileType::Mp4);
|
||||
assert!(MediaFileType::from_str("foo").is_err());
|
||||
}
|
||||
}
|
||||
@@ -238,7 +199,7 @@ mod tests {
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
let mut variants = MediaFileType::all_variants();
|
||||
assert_eq!(variants.len(), 17);
|
||||
assert_eq!(variants.len(), 13);
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileType::Audio));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileType::Image));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileType::Video));
|
||||
@@ -252,10 +213,6 @@ mod tests {
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileType::Vmd));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileType::Pmx));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileType::Csv));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileType::Jpg));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileType::Png));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileType::Gif));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileType::Mp4));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,77 +9,70 @@ use utoipa::ToSchema;
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize, ToSchema)]
|
||||
pub enum WeightsType {
|
||||
#[serde(rename = "hifigan_tt2")]
|
||||
HifiganTacotron2,
|
||||
#[serde(rename = "rvc_v2")]
|
||||
RvcV2,
|
||||
#[serde(rename = "sd_1.5")]
|
||||
StableDiffusion15,
|
||||
#[serde(rename = "sdxl")]
|
||||
StableDiffusionXL,
|
||||
#[serde(rename = "so_vits_svc")]
|
||||
SoVitsSvc,
|
||||
#[serde(rename = "tt2")]
|
||||
Tacotron2,
|
||||
#[serde(rename = "loRA")]
|
||||
LoRA,
|
||||
#[serde(rename = "vall_e")]
|
||||
VallE,
|
||||
#[serde(rename = "comfy_ui")]
|
||||
ComfyUi,
|
||||
|
||||
/// NB: IN production these are filtered to `PublicWeightsType::Tacotron25`.
|
||||
#[serde(rename = "gpt_so_vits")]
|
||||
GptSoVits,
|
||||
#[serde(rename = "hifigan_tt2")]
|
||||
HifiganTacotron2,
|
||||
#[serde(rename = "rvc_v2")]
|
||||
RvcV2,
|
||||
#[serde(rename = "sd_1.5")]
|
||||
StableDiffusion15,
|
||||
#[serde(rename = "sdxl")]
|
||||
StableDiffusionXL,
|
||||
#[serde(rename = "so_vits_svc")]
|
||||
SoVitsSvc,
|
||||
#[serde(rename = "tt2")]
|
||||
Tacotron2,
|
||||
#[serde(rename = "loRA")]
|
||||
LoRA,
|
||||
#[serde(rename = "vall_e")]
|
||||
VallE,
|
||||
#[serde(rename = "comfy_ui")]
|
||||
ComfyUi,
|
||||
}
|
||||
|
||||
|
||||
impl WeightsType {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::HifiganTacotron2 => "hifigan_tt2",
|
||||
Self::RvcV2 => "rvc_v2",
|
||||
Self::StableDiffusion15 => "sd_1.5",
|
||||
Self::StableDiffusionXL => "sdxl",
|
||||
Self::SoVitsSvc => "so_vits_svc",
|
||||
Self::Tacotron2 => "tt2",
|
||||
Self::LoRA => "loRA",
|
||||
Self::VallE => "vall_e",
|
||||
Self::ComfyUi => "comfy_ui",
|
||||
Self::GptSoVits => "gpt_so_vits",
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::HifiganTacotron2 => "hifigan_tt2",
|
||||
Self::RvcV2 => "rvc_v2",
|
||||
Self::StableDiffusion15 => "sd_1.5",
|
||||
Self::StableDiffusionXL => "sdxl",
|
||||
Self::SoVitsSvc => "so_vits_svc",
|
||||
Self::Tacotron2 => "tt2",
|
||||
Self::LoRA => "loRA",
|
||||
Self::VallE => "vall_e",
|
||||
Self::ComfyUi => "comfy_ui",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"hifigan_tt2" => Ok(Self::HifiganTacotron2),
|
||||
"rvc_v2" => Ok(Self::RvcV2),
|
||||
"sd_1.5" => Ok(Self::StableDiffusion15),
|
||||
"sdxl" => Ok(Self::StableDiffusionXL),
|
||||
"so_vits_svc" => Ok(Self::SoVitsSvc),
|
||||
"tt2" => Ok(Self::Tacotron2),
|
||||
"loRA" => Ok(Self::LoRA),
|
||||
"vall_e" => Ok(Self::VallE),
|
||||
"comfy_ui" => Ok(Self::ComfyUi),
|
||||
"gpt_so_vits" => Ok(Self::GptSoVits),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"hifigan_tt2" => Ok(Self::HifiganTacotron2),
|
||||
"rvc_v2" => Ok(Self::RvcV2),
|
||||
"sd_1.5" => Ok(Self::StableDiffusion15),
|
||||
"sdxl" => Ok(Self::StableDiffusionXL),
|
||||
"so_vits_svc" => Ok(Self::SoVitsSvc),
|
||||
"tt2" => Ok(Self::Tacotron2),
|
||||
"loRA" => Ok(Self::LoRA),
|
||||
"vall_e" => Ok(Self::VallE),
|
||||
"comfy_ui" => Ok(Self::ComfyUi),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<Self> {
|
||||
BTreeSet::from([
|
||||
Self::HifiganTacotron2,
|
||||
Self::RvcV2,
|
||||
Self::StableDiffusion15,
|
||||
Self::StableDiffusionXL,
|
||||
Self::SoVitsSvc,
|
||||
Self::Tacotron2,
|
||||
Self::LoRA,
|
||||
Self::VallE,
|
||||
Self::ComfyUi,
|
||||
Self::GptSoVits,
|
||||
])
|
||||
}
|
||||
pub fn all_variants() -> BTreeSet<Self> {
|
||||
BTreeSet::from([
|
||||
Self::HifiganTacotron2,
|
||||
Self::RvcV2,
|
||||
Self::StableDiffusion15,
|
||||
Self::StableDiffusionXL,
|
||||
Self::SoVitsSvc,
|
||||
Self::Tacotron2,
|
||||
Self::LoRA,
|
||||
Self::VallE,
|
||||
Self::ComfyUi,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
impl_enum_display_and_debug_using_to_str!(WeightsType);
|
||||
@@ -91,76 +84,44 @@ mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_to_str() {
|
||||
assert_eq!(WeightsType::HifiganTacotron2.to_str(), "hifigan_tt2");
|
||||
assert_eq!(WeightsType::RvcV2.to_str(), "rvc_v2");
|
||||
assert_eq!(WeightsType::StableDiffusion15.to_str(), "sd_1.5");
|
||||
assert_eq!(WeightsType::StableDiffusionXL.to_str(), "sdxl");
|
||||
assert_eq!(WeightsType::SoVitsSvc.to_str(), "so_vits_svc");
|
||||
assert_eq!(WeightsType::Tacotron2.to_str(), "tt2");
|
||||
assert_eq!(WeightsType::LoRA.to_str(), "loRA");
|
||||
assert_eq!(WeightsType::VallE.to_str(), "vall_e");
|
||||
assert_eq!(WeightsType::ComfyUi.to_str(), "comfy_ui");
|
||||
assert_eq!(WeightsType::GptSoVits.to_str(), "gpt_so_vits");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_str() {
|
||||
assert_eq!(WeightsType::from_str("hifigan_tt2").unwrap(), WeightsType::HifiganTacotron2);
|
||||
assert_eq!(WeightsType::from_str("rvc_v2").unwrap(), WeightsType::RvcV2);
|
||||
assert_eq!(WeightsType::from_str("sd_1.5").unwrap(), WeightsType::StableDiffusion15);
|
||||
assert_eq!(WeightsType::from_str("sdxl").unwrap(), WeightsType::StableDiffusionXL);
|
||||
assert_eq!(WeightsType::from_str("so_vits_svc").unwrap(), WeightsType::SoVitsSvc);
|
||||
assert_eq!(WeightsType::from_str("tt2").unwrap(), WeightsType::Tacotron2);
|
||||
assert_eq!(WeightsType::from_str("loRA").unwrap(), WeightsType::LoRA);
|
||||
assert_eq!(WeightsType::from_str("vall_e").unwrap(), WeightsType::VallE);
|
||||
assert_eq!(WeightsType::from_str("comfy_ui").unwrap(), WeightsType::ComfyUi);
|
||||
assert_eq!(WeightsType::from_str("gpt_so_vits").unwrap(), WeightsType::GptSoVits);
|
||||
assert!(WeightsType::from_str("invalid").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_all_variants() {
|
||||
let variants = WeightsType::all_variants();
|
||||
assert_eq!(variants.len(), 10);
|
||||
assert!(variants.contains(&WeightsType::HifiganTacotron2));
|
||||
assert!(variants.contains(&WeightsType::RvcV2));
|
||||
assert!(variants.contains(&WeightsType::StableDiffusion15));
|
||||
assert!(variants.contains(&WeightsType::StableDiffusionXL));
|
||||
assert!(variants.contains(&WeightsType::SoVitsSvc));
|
||||
assert!(variants.contains(&WeightsType::Tacotron2));
|
||||
assert!(variants.contains(&WeightsType::LoRA));
|
||||
assert!(variants.contains(&WeightsType::VallE));
|
||||
assert!(variants.contains(&WeightsType::ComfyUi));
|
||||
assert!(variants.contains(&WeightsType::GptSoVits));
|
||||
}
|
||||
|
||||
mod mechanical_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn variant_length() {
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(WeightsType::all_variants().len(), WeightsType::iter().len());
|
||||
fn test_to_str() {
|
||||
assert_eq!(WeightsType::HifiganTacotron2.to_str(), "hifigan_tt2");
|
||||
assert_eq!(WeightsType::RvcV2.to_str(), "rvc_v2");
|
||||
assert_eq!(WeightsType::StableDiffusion15.to_str(), "sd_1.5");
|
||||
assert_eq!(WeightsType::StableDiffusionXL.to_str(), "sdxl");
|
||||
assert_eq!(WeightsType::SoVitsSvc.to_str(), "so_vits_svc");
|
||||
assert_eq!(WeightsType::Tacotron2.to_str(), "tt2");
|
||||
assert_eq!(WeightsType::LoRA.to_str(), "loRA");
|
||||
assert_eq!(WeightsType::VallE.to_str(), "vall_e");
|
||||
assert_eq!(WeightsType::ComfyUi.to_str(), "comfy_ui");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip() {
|
||||
for variant in WeightsType::all_variants() {
|
||||
assert_eq!(variant, WeightsType::from_str(variant.to_str()).unwrap());
|
||||
assert_eq!(variant, WeightsType::from_str(&format!("{}", variant)).unwrap());
|
||||
assert_eq!(variant, WeightsType::from_str(&format!("{:?}", variant)).unwrap());
|
||||
}
|
||||
fn test_from_str() {
|
||||
assert_eq!(WeightsType::from_str("hifigan_tt2").unwrap(), WeightsType::HifiganTacotron2);
|
||||
assert_eq!(WeightsType::from_str("rvc_v2").unwrap(), WeightsType::RvcV2);
|
||||
assert_eq!(WeightsType::from_str("sd_1.5").unwrap(), WeightsType::StableDiffusion15);
|
||||
assert_eq!(WeightsType::from_str("sdxl").unwrap(), WeightsType::StableDiffusionXL);
|
||||
assert_eq!(WeightsType::from_str("so_vits_svc").unwrap(), WeightsType::SoVitsSvc);
|
||||
assert_eq!(WeightsType::from_str("tt2").unwrap(), WeightsType::Tacotron2);
|
||||
assert_eq!(WeightsType::from_str("loRA").unwrap(), WeightsType::LoRA);
|
||||
assert_eq!(WeightsType::from_str("vall_e").unwrap(), WeightsType::VallE);
|
||||
assert_eq!(WeightsType::from_str("comfy_ui").unwrap(), WeightsType::ComfyUi);
|
||||
assert!(WeightsType::from_str("invalid").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialized_length_ok_for_database() {
|
||||
const MAX_LENGTH : usize = 16;
|
||||
for variant in WeightsType::all_variants() {
|
||||
let serialized = variant.to_str();
|
||||
assert!(serialized.len() > 0, "variant {:?} is too short", variant);
|
||||
assert!(serialized.len() <= MAX_LENGTH, "variant {:?} is too long", variant);
|
||||
}
|
||||
fn test_all_variants() {
|
||||
let variants = WeightsType::all_variants();
|
||||
assert_eq!(variants.len(), 9);
|
||||
assert!(variants.contains(&WeightsType::HifiganTacotron2));
|
||||
assert!(variants.contains(&WeightsType::RvcV2));
|
||||
assert!(variants.contains(&WeightsType::StableDiffusion15));
|
||||
assert!(variants.contains(&WeightsType::StableDiffusionXL));
|
||||
assert!(variants.contains(&WeightsType::SoVitsSvc));
|
||||
assert!(variants.contains(&WeightsType::Tacotron2));
|
||||
assert!(variants.contains(&WeightsType::LoRA));
|
||||
assert!(variants.contains(&WeightsType::VallE));
|
||||
assert!(variants.contains(&WeightsType::ComfyUi));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,10 +124,10 @@ mod tests {
|
||||
fn serialize() {
|
||||
let expected = "\"positive\"".to_string(); // NB: Quoted
|
||||
|
||||
assert_eq!(expected, serde_json::to_string(&UserRatingValue::Positive).unwrap());
|
||||
assert_eq!(expected, toml::to_string(&UserRatingValue::Positive).unwrap());
|
||||
|
||||
// Just to show this serializes the same as a string
|
||||
assert_eq!(expected, serde_json::to_string("positive").unwrap());
|
||||
assert_eq!(expected, toml::to_string("positive").unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -112,10 +112,10 @@ mod tests {
|
||||
fn serialize() {
|
||||
let expected = "\"author\"".to_string(); // NB: Quoted
|
||||
|
||||
assert_eq!(expected, serde_json::to_string(&ViewAs::Author).unwrap());
|
||||
assert_eq!(expected, toml::to_string(&ViewAs::Author).unwrap());
|
||||
|
||||
// Just to show this serializes the same as a string
|
||||
assert_eq!(expected, serde_json::to_string("author").unwrap());
|
||||
assert_eq!(expected, toml::to_string("author").unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -153,10 +153,10 @@ mod tests {
|
||||
fn serialize() {
|
||||
let expected = "\"public\"".to_string(); // NB: Quoted
|
||||
|
||||
assert_eq!(expected, serde_json::to_string(&Visibility::Public).unwrap());
|
||||
assert_eq!(expected, toml::to_string(&Visibility::Public).unwrap());
|
||||
|
||||
// Just to show this serializes the same as a string
|
||||
assert_eq!(expected, serde_json::to_string("public").unwrap());
|
||||
assert_eq!(expected, toml::to_string("public").unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
pub mod premium_product;
|
||||
pub mod style_transfer;
|
||||
@@ -1 +0,0 @@
|
||||
pub mod premium_product_name;
|
||||
@@ -1,134 +0,0 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// This enum is not backed by a particular database table.
|
||||
/// This is used to count premium product uses for free and paid users.
|
||||
///
|
||||
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Deserialize, Serialize, ToSchema)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum PremiumProductName {
|
||||
// NB: These keys are kept short to preserve space
|
||||
#[serde(rename = "fa")]
|
||||
FaceAnimator,
|
||||
// NB: These keys are kept short to preserve space
|
||||
#[serde(rename = "fm")]
|
||||
FaceMirror,
|
||||
// NB: These keys are kept short to preserve space
|
||||
#[serde(rename = "lip")]
|
||||
Lipsync,
|
||||
// NB: These keys are kept short to preserve space
|
||||
#[serde(rename = "vst")]
|
||||
VideoStyleTransfer,
|
||||
}
|
||||
|
||||
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
|
||||
impl_enum_display_and_debug_using_to_str!(PremiumProductName);
|
||||
//impl_mysql_enum_coders!(PremiumProductName);
|
||||
//impl_mysql_from_row!(PremiumProductName);
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl PremiumProductName {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::FaceAnimator => "fa",
|
||||
Self::FaceMirror => "fm",
|
||||
Self::Lipsync => "lip",
|
||||
Self::VideoStyleTransfer => "vst",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"fa" => Ok(Self::FaceAnimator),
|
||||
"fm" => Ok(Self::FaceMirror),
|
||||
"lip" => Ok(Self::Lipsync),
|
||||
"vst" => Ok(Self::VideoStyleTransfer),
|
||||
_ => Err(format!("Unknown PremiumProductName: {}", value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<Self> {
|
||||
// NB: BTreeSet is sorted
|
||||
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
|
||||
BTreeSet::from([
|
||||
Self::FaceAnimator,
|
||||
Self::FaceMirror,
|
||||
Self::Lipsync,
|
||||
Self::VideoStyleTransfer,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::no_table::premium_product::premium_product_name::PremiumProductName;
|
||||
use crate::test_helpers::assert_serialization;
|
||||
|
||||
mod serde {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(PremiumProductName::FaceAnimator, "fa");
|
||||
assert_serialization(PremiumProductName::FaceMirror, "fm");
|
||||
assert_serialization(PremiumProductName::Lipsync, "lip");
|
||||
assert_serialization(PremiumProductName::VideoStyleTransfer, "vst");
|
||||
}
|
||||
|
||||
mod impl_methods {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn to_str() {
|
||||
assert_eq!(PremiumProductName::FaceAnimator.to_str(), "fa");
|
||||
assert_eq!(PremiumProductName::FaceMirror.to_str(), "fm");
|
||||
assert_eq!(PremiumProductName::Lipsync.to_str(), "lip");
|
||||
assert_eq!(PremiumProductName::VideoStyleTransfer.to_str(), "vst");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_str() {
|
||||
assert_eq!(PremiumProductName::from_str("fa").unwrap(), PremiumProductName::FaceAnimator);
|
||||
assert_eq!(PremiumProductName::from_str("fm").unwrap(), PremiumProductName::FaceMirror);
|
||||
assert_eq!(PremiumProductName::from_str("lip").unwrap(), PremiumProductName::Lipsync);
|
||||
assert_eq!(PremiumProductName::from_str("vst").unwrap(), PremiumProductName::VideoStyleTransfer);
|
||||
}
|
||||
}
|
||||
|
||||
mod manual_variant_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
let variants = PremiumProductName::all_variants();
|
||||
assert_eq!(variants.len(), 4);
|
||||
}
|
||||
}
|
||||
|
||||
mod mechanical_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn variant_length() {
|
||||
use strum::IntoEnumIterator;
|
||||
assert_eq!(PremiumProductName::all_variants().len(), PremiumProductName::iter().len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn round_trip() {
|
||||
for variant in PremiumProductName::all_variants() {
|
||||
assert_eq!(variant, PremiumProductName::from_str(variant.to_str()).unwrap());
|
||||
assert_eq!(variant, PremiumProductName::from_str(&format!("{}", variant)).unwrap());
|
||||
assert_eq!(variant, PremiumProductName::from_str(&format!("{:?}", variant)).unwrap());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -84,10 +84,6 @@ pub enum StyleTransferName {
|
||||
#[serde(rename = "realistic_cyberpunk")]
|
||||
RealisticCyberpunk,
|
||||
|
||||
// New Styles (2024-06-27)
|
||||
|
||||
#[serde(rename = "dreamer")] // TODO: Land this in Gitub
|
||||
Dreamer,
|
||||
}
|
||||
|
||||
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
|
||||
@@ -134,9 +130,6 @@ impl StyleTransferName {
|
||||
Self::Dragonball => "dragonball",
|
||||
Self::RealisticMatrix => "realistic_matrix",
|
||||
Self::RealisticCyberpunk => "realistic_cyberpunk",
|
||||
|
||||
// New Styles (2024-06-27)
|
||||
Self::Dreamer => "dreamer",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,7 +169,6 @@ impl StyleTransferName {
|
||||
"dragonball" => Ok(Self::Dragonball),
|
||||
"realistic_matrix" => Ok(Self::RealisticMatrix),
|
||||
"realistic_cyberpunk" => Ok(Self::RealisticCyberpunk),
|
||||
"dreamer" => Ok(Self::Dreamer),
|
||||
_ => Err(format!("Unknown StyleTransferName: {}", value)),
|
||||
}
|
||||
}
|
||||
@@ -217,7 +209,6 @@ impl StyleTransferName {
|
||||
Self::Dragonball => "31_dragonball.json",
|
||||
Self::RealisticMatrix => "32_realistic_matrix.json",
|
||||
Self::RealisticCyberpunk => "33_realistic_cyberpunk.json",
|
||||
Self::Dreamer => "34_dreamer.json",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,8 +250,6 @@ impl StyleTransferName {
|
||||
Self::Dragonball,
|
||||
Self::RealisticMatrix,
|
||||
Self::RealisticCyberpunk,
|
||||
|
||||
Self::Dreamer,
|
||||
])
|
||||
}
|
||||
}
|
||||
@@ -309,8 +298,6 @@ mod tests {
|
||||
assert_serialization(StyleTransferName::Dragonball, "dragonball");
|
||||
assert_serialization(StyleTransferName::RealisticMatrix, "realistic_matrix");
|
||||
assert_serialization(StyleTransferName::RealisticCyberpunk, "realistic_cyberpunk");
|
||||
|
||||
assert_serialization(StyleTransferName::Dreamer, "dreamer");
|
||||
}
|
||||
|
||||
mod impl_methods {
|
||||
@@ -352,8 +339,6 @@ mod tests {
|
||||
assert_eq!(StyleTransferName::Dragonball.to_str(), "dragonball");
|
||||
assert_eq!(StyleTransferName::RealisticMatrix.to_str(), "realistic_matrix");
|
||||
assert_eq!(StyleTransferName::RealisticCyberpunk.to_str(), "realistic_cyberpunk");
|
||||
|
||||
assert_eq!(StyleTransferName::Dreamer.to_str(), "dreamer");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -393,8 +378,6 @@ mod tests {
|
||||
assert_eq!(StyleTransferName::from_str("realistic_matrix").unwrap(), StyleTransferName::RealisticMatrix);
|
||||
assert_eq!(StyleTransferName::from_str("realistic_cyberpunk").unwrap(), StyleTransferName::RealisticCyberpunk);
|
||||
|
||||
assert_eq!(StyleTransferName::from_str("dreamer").unwrap(), StyleTransferName::Dreamer);
|
||||
|
||||
assert!(StyleTransferName::from_str("foo").is_err());
|
||||
}
|
||||
}
|
||||
@@ -405,7 +388,7 @@ mod tests {
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
let variants = StyleTransferName::all_variants();
|
||||
assert_eq!(variants.len(), 34);
|
||||
assert_eq!(variants.len(), 33);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,12 +3,9 @@
|
||||
use serde::Serialize;
|
||||
|
||||
pub fn to_toml<T: Serialize>(t: &T) -> String {
|
||||
match toml::to_string(t) {
|
||||
Ok(s) => s.replace("\"", ""), // JSON values are quoted, so we remove quotes
|
||||
Err(err) => {
|
||||
panic!("serialization error: {}", err);
|
||||
}
|
||||
}
|
||||
toml::to_string(t)
|
||||
.expect("serialization error")
|
||||
.replace("\"", "") // JSON values are quoted, so we remove quotes
|
||||
}
|
||||
|
||||
pub fn to_json<T: Serialize>(t: &T) -> String {
|
||||
@@ -21,7 +18,6 @@ pub fn to_json<T: Serialize>(t: &T) -> String {
|
||||
/// This is useful for ensuring stability of serialization.
|
||||
pub fn assert_serialization<T: Serialize>(t: T, expected: &str) {
|
||||
// TODO: See if there's a way to check the sqlx serialization
|
||||
// TODO(bt,2024-06-27): Something broke with serde toml serialization, so we're disabling it
|
||||
// assert_eq!(&to_toml(&t), expected);
|
||||
assert_eq!(&to_toml(&t), expected);
|
||||
assert_eq!(&to_json(&t), expected);
|
||||
}
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
[package]
|
||||
name = "enums_public"
|
||||
edition = "2018"
|
||||
version = "0.0.1"
|
||||
authors = [
|
||||
"Brandon Thomas <bt@brand.io>",
|
||||
"Brandon Thomas <echelon@gmail.com>",
|
||||
]
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
name = "enums_public"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
normal = ["my-workspace-hack"]
|
||||
|
||||
[dependencies]
|
||||
# Internal
|
||||
enums = { path = "../enums" }
|
||||
errors = { path = "../../lib/errors" }
|
||||
|
||||
# Workspace hack (faster compile times)
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
# Serialization
|
||||
serde = "1.0.125"
|
||||
serde_derive = "1.0.125"
|
||||
|
||||
utoipa = { version = "4", features = ["chrono","actix_extras"] }
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
# Enum utilities
|
||||
strum = { version = "0.26", features = ["derive"] }
|
||||
|
||||
# Test serialization
|
||||
serde_json = "1.0.108"
|
||||
toml = "0.8.14"
|
||||
@@ -1 +0,0 @@
|
||||
pub mod public_inference_job_type;
|
||||
-212
@@ -1,212 +0,0 @@
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
use enums::by_table::generic_inference_jobs::inference_job_type::InferenceJobType;
|
||||
|
||||
/// Report certain jobs publicly as different from what we actually run.
|
||||
/// This is so we have an edge against the competition that might try to run
|
||||
/// the same models or workflows. This won't always make sense, but in some cases it will.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize, Default, ToSchema, Debug)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum PublicInferenceJobType {
|
||||
// Renamed enum variants
|
||||
|
||||
/// Instead of `InferenceJobType::LivePortrait` ("live_portrait")
|
||||
ActingFace,
|
||||
|
||||
/// Storyteller Studio and Video Style Transfer Jobs (which we may want to split).
|
||||
/// These run in Comfy.
|
||||
/// TODO(bt,2024-07-15): We may segregate these two job types in the future
|
||||
VideoRender,
|
||||
|
||||
GptSovits,
|
||||
|
||||
// Everything else is the same
|
||||
|
||||
/// Jobs that run ComfyUI workflows
|
||||
/// This is actually just for Video Style Transfer and Storyteller Studio.
|
||||
#[deprecated(note = "Use VideoRender instead.")]
|
||||
ComfyUi,
|
||||
|
||||
/// A job that turns "FBX" game engine files into "GLTF" files (Bevy-compatible).
|
||||
#[serde(rename = "convert_fbx_gltf")]
|
||||
ConvertFbxToGltf,
|
||||
|
||||
/// Process a video into BVH mocap animation data for game engines
|
||||
MocapNet,
|
||||
|
||||
/// RVC is a voice conversion model. RVCv2 is the most popular such model currently.
|
||||
#[serde(rename = "rvc_v2")]
|
||||
RvcV2,
|
||||
|
||||
/// SadTalker does image-to-video lip-syncing when given an audio file and image.
|
||||
SadTalker,
|
||||
|
||||
/// so-vits-svc voice conversion. This predates RVCv2.
|
||||
SoVitsSvc,
|
||||
|
||||
/// Stable diffusion image generation
|
||||
StableDiffusion,
|
||||
|
||||
/// StyleTTS2 is a zero shot multi-speaker TTS model.
|
||||
/// This job type should handle both speaker vector encoding and inference.
|
||||
#[serde(rename = "styletts2")]
|
||||
StyleTTS2,
|
||||
|
||||
/// TT2 Text to speech
|
||||
Tacotron2,
|
||||
|
||||
/// A value we may use in the future for historical jobs
|
||||
/// (i.e. when we backfill the database column and make it non-nullable)
|
||||
#[default]
|
||||
Unknown,
|
||||
|
||||
/// DEPRECATED. DO NOT USE.
|
||||
/// Job that converts bevy to workflow files
|
||||
#[deprecated(note = "This was for Bevy engine's server side rendering.")]
|
||||
#[serde(rename = "bevy_to_workflow")]
|
||||
BevyToWorkflow,
|
||||
|
||||
#[deprecated(note = "This was for ReRenderAVideo, which we never productionized.")]
|
||||
/// DEPRECATED. DO NOT USE.
|
||||
/// Re-render a video is a video style transfer algorithm. We developed code
|
||||
/// around it, but chose to develop AnimateDiff / ComfyUI support instead.
|
||||
RerenderAVideo,
|
||||
}
|
||||
|
||||
/// NB: Legacy API for older code.
|
||||
impl PublicInferenceJobType {
|
||||
|
||||
pub fn from_enum(inference_job_type: InferenceJobType) -> Self {
|
||||
match inference_job_type {
|
||||
// Renamed variants
|
||||
InferenceJobType::LivePortrait => Self::ActingFace,
|
||||
// Conserved variants
|
||||
InferenceJobType::VideoRender => Self::VideoRender,
|
||||
InferenceJobType::GptSovits => Self::GptSovits,
|
||||
InferenceJobType::ComfyUi => Self::ComfyUi,
|
||||
InferenceJobType::ConvertFbxToGltf => Self::ConvertFbxToGltf,
|
||||
InferenceJobType::MocapNet => Self::MocapNet,
|
||||
InferenceJobType::RvcV2 => Self::RvcV2,
|
||||
InferenceJobType::SadTalker => Self::SadTalker,
|
||||
InferenceJobType::SoVitsSvc => Self::SoVitsSvc,
|
||||
InferenceJobType::StableDiffusion => Self::StableDiffusion,
|
||||
InferenceJobType::StyleTTS2 => Self::StyleTTS2,
|
||||
InferenceJobType::Tacotron2 => Self::Tacotron2,
|
||||
InferenceJobType::Unknown => Self::Unknown,
|
||||
InferenceJobType::BevyToWorkflow => Self::BevyToWorkflow,
|
||||
InferenceJobType::RerenderAVideo => Self::RerenderAVideo,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_enum(&self) -> InferenceJobType {
|
||||
match self {
|
||||
// Renamed variants
|
||||
Self::ActingFace => InferenceJobType::LivePortrait,
|
||||
// Conserved variants
|
||||
Self::VideoRender => InferenceJobType::VideoRender,
|
||||
Self::GptSovits => InferenceJobType::GptSovits,
|
||||
Self::ComfyUi => InferenceJobType::ComfyUi,
|
||||
Self::ConvertFbxToGltf => InferenceJobType::ConvertFbxToGltf,
|
||||
Self::MocapNet => InferenceJobType::MocapNet,
|
||||
Self::RvcV2 => InferenceJobType::RvcV2,
|
||||
Self::SadTalker => InferenceJobType::SadTalker,
|
||||
Self::SoVitsSvc => InferenceJobType::SoVitsSvc,
|
||||
Self::StableDiffusion => InferenceJobType::StableDiffusion,
|
||||
Self::StyleTTS2 => InferenceJobType::StyleTTS2,
|
||||
Self::Tacotron2 => InferenceJobType::Tacotron2,
|
||||
Self::Unknown => InferenceJobType::Unknown,
|
||||
Self::BevyToWorkflow => InferenceJobType::BevyToWorkflow,
|
||||
Self::RerenderAVideo => InferenceJobType::RerenderAVideo,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use crate::test_helpers::to_json;
|
||||
|
||||
use super::*;
|
||||
|
||||
fn override_enums() -> &'static [PublicInferenceJobType; 1] {
|
||||
&[
|
||||
PublicInferenceJobType::ActingFace,
|
||||
]
|
||||
}
|
||||
|
||||
mod override_values {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn acting_face() {
|
||||
// Public --> Internal
|
||||
assert_eq!(PublicInferenceJobType::ActingFace.to_enum(), InferenceJobType::LivePortrait);
|
||||
assert_eq!(to_json(&PublicInferenceJobType::ActingFace.to_enum()), "live_portrait");
|
||||
|
||||
// Internal --> Public
|
||||
assert_eq!(PublicInferenceJobType::from_enum(InferenceJobType::LivePortrait), PublicInferenceJobType::ActingFace);
|
||||
assert_eq!(to_json(&PublicInferenceJobType::from_enum(InferenceJobType::LivePortrait)), "acting_face");
|
||||
}
|
||||
}
|
||||
|
||||
mod mechanical_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn public_to_internal() {
|
||||
let mut tested_count = 0;
|
||||
|
||||
for public_variant in PublicInferenceJobType::iter() {
|
||||
if public_variant == PublicInferenceJobType::ActingFace {
|
||||
continue; // Can't compare.
|
||||
}
|
||||
|
||||
// Round trip
|
||||
assert_eq!(public_variant, PublicInferenceJobType::from_enum(public_variant.to_enum()));
|
||||
|
||||
let internal_enum_variant = public_variant.to_enum();
|
||||
let internal_enum_string = to_json(&internal_enum_variant);
|
||||
let public_enum_string = to_json(&public_variant);
|
||||
|
||||
assert_eq!(internal_enum_string, public_enum_string);
|
||||
|
||||
tested_count += 1;
|
||||
}
|
||||
|
||||
assert!(tested_count > 1);
|
||||
assert_eq!(tested_count, PublicInferenceJobType::iter().len() - override_enums().len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn internal_to_public() {
|
||||
let mut tested_count = 0;
|
||||
|
||||
for internal_variant in InferenceJobType::all_variants() {
|
||||
if internal_variant == InferenceJobType::LivePortrait {
|
||||
continue; // Can't compare.
|
||||
}
|
||||
|
||||
// Round trip
|
||||
assert_eq!(internal_variant, PublicInferenceJobType::from_enum(internal_variant).to_enum());
|
||||
|
||||
let public_enum_variant = PublicInferenceJobType::from_enum(internal_variant);
|
||||
let public_enum_string = to_json(&public_enum_variant);
|
||||
let internal_enum_string = to_json(&internal_variant);
|
||||
|
||||
// Same serialization
|
||||
assert_eq!(internal_enum_string, public_enum_string);
|
||||
|
||||
tested_count += 1;
|
||||
}
|
||||
|
||||
assert!(tested_count > 1);
|
||||
assert_eq!(tested_count, InferenceJobType::all_variants().len() - override_enums().len());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
pub mod generic_inference_jobs;
|
||||
pub mod model_weights;
|
||||
@@ -1 +0,0 @@
|
||||
pub mod public_weights_types;
|
||||
@@ -1,162 +0,0 @@
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
use enums::by_table::model_weights::weights_types::WeightsType;
|
||||
|
||||
/// Report certain models publicly as different from what we actually use.
|
||||
/// This is so we have an edge against the competition that might try to run
|
||||
/// the same models. This won't always make sense, but in some cases it will.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize, ToSchema, Debug)]
|
||||
pub enum PublicWeightsType {
|
||||
// Renamed enum variants
|
||||
|
||||
/// Instead of `WeightsType::GptSoVits` ("gpt_so_vits")
|
||||
#[serde(rename = "tacotron2.5")]
|
||||
Tacotron2_5,
|
||||
|
||||
// Everything else is the same
|
||||
|
||||
#[serde(rename = "hifigan_tt2")]
|
||||
HifiganTacotron2,
|
||||
#[serde(rename = "rvc_v2")]
|
||||
RvcV2,
|
||||
#[serde(rename = "sd_1.5")]
|
||||
StableDiffusion15,
|
||||
#[serde(rename = "sdxl")]
|
||||
StableDiffusionXL,
|
||||
#[serde(rename = "so_vits_svc")]
|
||||
SoVitsSvc,
|
||||
#[serde(rename = "tt2")]
|
||||
Tacotron2,
|
||||
#[serde(rename = "loRA")]
|
||||
LoRA,
|
||||
#[serde(rename = "vall_e")]
|
||||
VallE,
|
||||
#[serde(rename = "comfy_ui")]
|
||||
ComfyUi,
|
||||
}
|
||||
|
||||
impl PublicWeightsType {
|
||||
pub fn from_enum(weights_type: WeightsType) -> Self {
|
||||
match weights_type {
|
||||
// Renamed variants
|
||||
WeightsType::GptSoVits => Self::Tacotron2_5,
|
||||
// Conserved variants
|
||||
WeightsType::HifiganTacotron2 => Self::HifiganTacotron2,
|
||||
WeightsType::RvcV2 => Self::RvcV2,
|
||||
WeightsType::StableDiffusion15 => Self::StableDiffusion15,
|
||||
WeightsType::StableDiffusionXL => Self::StableDiffusionXL,
|
||||
WeightsType::SoVitsSvc => Self::SoVitsSvc,
|
||||
WeightsType::Tacotron2 => Self::Tacotron2,
|
||||
WeightsType::LoRA => Self::LoRA,
|
||||
WeightsType::VallE => Self::VallE,
|
||||
WeightsType::ComfyUi => Self::ComfyUi,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_enum(&self) -> WeightsType {
|
||||
match self {
|
||||
// Renamed variants
|
||||
Self::Tacotron2_5 => WeightsType::GptSoVits,
|
||||
// Conserved variants
|
||||
Self::HifiganTacotron2 => WeightsType::HifiganTacotron2,
|
||||
Self::RvcV2 => WeightsType::RvcV2,
|
||||
Self::StableDiffusion15 => WeightsType::StableDiffusion15,
|
||||
Self::StableDiffusionXL => WeightsType::StableDiffusionXL,
|
||||
Self::SoVitsSvc => WeightsType::SoVitsSvc,
|
||||
Self::Tacotron2 => WeightsType::Tacotron2,
|
||||
Self::LoRA => WeightsType::LoRA,
|
||||
Self::VallE => WeightsType::VallE,
|
||||
Self::ComfyUi => WeightsType::ComfyUi,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use crate::test_helpers::to_json;
|
||||
|
||||
use super::*;
|
||||
|
||||
fn override_enums() -> &'static [PublicWeightsType; 1] {
|
||||
&[
|
||||
PublicWeightsType::Tacotron2_5,
|
||||
]
|
||||
}
|
||||
|
||||
mod override_values {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn gpt_so_vits() {
|
||||
// Public --> Internal
|
||||
assert_eq!(PublicWeightsType::Tacotron2_5.to_enum(), WeightsType::GptSoVits);
|
||||
assert_eq!(to_json(&PublicWeightsType::Tacotron2_5.to_enum()), "gpt_so_vits");
|
||||
|
||||
// Internal --> Public
|
||||
assert_eq!(PublicWeightsType::from_enum(WeightsType::GptSoVits), PublicWeightsType::Tacotron2_5);
|
||||
assert_eq!(to_json(&PublicWeightsType::from_enum(WeightsType::GptSoVits)), "tacotron2.5");
|
||||
}
|
||||
}
|
||||
|
||||
mod mechanical_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn public_to_internal() {
|
||||
let mut tested_count = 0;
|
||||
|
||||
for public_variant in PublicWeightsType::iter() {
|
||||
if public_variant == PublicWeightsType::Tacotron2_5 {
|
||||
continue; // Can't compare.
|
||||
}
|
||||
|
||||
// Round trip
|
||||
assert_eq!(public_variant, PublicWeightsType::from_enum(public_variant.to_enum()));
|
||||
|
||||
let internal_enum_variant = public_variant.to_enum();
|
||||
let internal_enum_string = to_json(&internal_enum_variant);
|
||||
let public_enum_string = to_json(&public_variant);
|
||||
|
||||
assert_eq!(internal_enum_string, public_enum_string);
|
||||
|
||||
tested_count += 1;
|
||||
}
|
||||
|
||||
assert!(tested_count > 1);
|
||||
assert_eq!(tested_count, PublicWeightsType::iter().len() - override_enums().len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn internal_to_public() {
|
||||
let mut tested_count = 0;
|
||||
|
||||
for internal_variant in WeightsType::all_variants() {
|
||||
if internal_variant == WeightsType::GptSoVits {
|
||||
continue; // Can't compare.
|
||||
}
|
||||
|
||||
// Round trip
|
||||
assert_eq!(internal_variant, PublicWeightsType::from_enum(internal_variant).to_enum());
|
||||
|
||||
let public_enum_variant = PublicWeightsType::from_enum(internal_variant);
|
||||
let public_enum_string = to_json(&public_enum_variant);
|
||||
let internal_enum_string = to_json(&internal_variant);
|
||||
|
||||
// Same serialization
|
||||
assert_eq!(internal_enum_string, public_enum_string);
|
||||
|
||||
tested_count += 1;
|
||||
}
|
||||
|
||||
assert!(tested_count > 1);
|
||||
assert_eq!(tested_count, WeightsType::all_variants().len() - override_enums().len());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
//! enums_public
|
||||
//!
|
||||
//! Sometimes we want to hide which enums we allow over the API
|
||||
//! to keep competitors in the dark about what we're doing.
|
||||
//!
|
||||
|
||||
// Never allow these
|
||||
#![forbid(private_bounds)]
|
||||
#![forbid(private_interfaces)]
|
||||
#![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)]
|
||||
|
||||
#[macro_use] extern crate serde_derive;
|
||||
|
||||
#[cfg(test)] pub mod test_helpers;
|
||||
|
||||
pub mod by_table;
|
||||
@@ -1,27 +0,0 @@
|
||||
//! Only imported in tests
|
||||
|
||||
use serde::Serialize;
|
||||
|
||||
pub fn to_toml<T: Serialize>(t: &T) -> String {
|
||||
match toml::to_string(t) {
|
||||
Ok(s) => s.replace("\"", ""), // JSON values are quoted, so we remove quotes
|
||||
Err(err) => {
|
||||
panic!("serialization error: {}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_json<T: Serialize>(t: &T) -> String {
|
||||
serde_json::to_string(t)
|
||||
.expect("serialization error")
|
||||
.replace("\"", "") // JSON values are quoted, so we remove quotes
|
||||
}
|
||||
|
||||
/// Assert that the Serialize is represented by the expected string value.
|
||||
/// This is useful for ensuring stability of serialization.
|
||||
pub fn assert_serialization<T: Serialize>(t: T, expected: &str) {
|
||||
// TODO: See if there's a way to check the sqlx serialization
|
||||
// TODO(bt,2024-06-27): Something broke with serde toml serialization, so we're disabling it
|
||||
// assert_eq!(&to_toml(&t), expected);
|
||||
assert_eq!(&to_json(&t), expected);
|
||||
}
|
||||
@@ -36,4 +36,4 @@ sqlx = { version = "0.7.2", features = [ "mysql", "runtime-tokio", "tls-rustls",
|
||||
[dev-dependencies]
|
||||
# Test serialization
|
||||
#serde_json = "1.0.64"
|
||||
toml = "0.8.14"
|
||||
toml = "0.5.8"
|
||||
|
||||
@@ -41,8 +41,8 @@ utoipa = { version = "4", features = ["chrono","actix_extras"] }
|
||||
[dev-dependencies]
|
||||
|
||||
# Enum utilities
|
||||
strum = { version = "0.26", features = ["derive"] }
|
||||
strum = { version = "0.25", features = ["derive"] }
|
||||
|
||||
# Test serialization
|
||||
serde_json = "1.0.108"
|
||||
toml = "0.8.14"
|
||||
toml = "0.5.8"
|
||||
|
||||
@@ -12,5 +12,4 @@ use crate::prefixes::TokenPrefix;
|
||||
pub struct MediaFileToken(pub String);
|
||||
|
||||
impl_string_token!(MediaFileToken);
|
||||
impl_mysql_token_from_row!(MediaFileToken);
|
||||
impl_crockford_generator!(MediaFileToken, 32usize, TokenPrefix::MediaFile, CrockfordLower);
|
||||
|
||||
@@ -40,7 +40,7 @@ clap = "4.4.8"
|
||||
rand = "0.8.5"
|
||||
# Runtime
|
||||
# NB: We switched to Tokio from `async-std` for broader ecosystem support.
|
||||
tokio = { version = "1.38.0", features = ["macros"] }
|
||||
tokio = { version = "1.34.0", features = ["macros"] }
|
||||
|
||||
sqlx = { version = "0.7.2", features = [ "mysql", "runtime-tokio", "tls-rustls", "chrono" ] }
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ pub fn get_bucket_clients() -> AnyhowResult<BucketClients> {
|
||||
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 s3_compatible_endpoint_url = easyenv::get_env_string_or_default("S3_COMPATIBLE_ENDPOINT_URL", "https://storage.googleapis.com");
|
||||
|
||||
// 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.
|
||||
@@ -30,7 +29,6 @@ pub fn get_bucket_clients() -> AnyhowResult<BucketClients> {
|
||||
&secret_key,
|
||||
®ion_name,
|
||||
&public_bucket_name,
|
||||
&s3_compatible_endpoint_url,
|
||||
None,
|
||||
Some(bucket_timeout),
|
||||
)?;
|
||||
@@ -42,7 +40,6 @@ pub fn get_bucket_clients() -> AnyhowResult<BucketClients> {
|
||||
&secret_key,
|
||||
®ion_name,
|
||||
&private_bucket_name,
|
||||
&s3_compatible_endpoint_url,
|
||||
None,
|
||||
Some(bucket_timeout),
|
||||
)?;
|
||||
|
||||
@@ -37,7 +37,7 @@ log = "0.4.14"
|
||||
|
||||
# Runtime
|
||||
# NB: We switched to Tokio from `async-std` for broader ecosystem support.
|
||||
tokio = { version = "1.38.0", features = ["macros"] }
|
||||
tokio = { version = "1.34.0", features = ["macros"] }
|
||||
|
||||
sqlx = { version = "0.7.2", features = [ "mysql", "runtime-tokio", "tls-rustls", "chrono" ] }
|
||||
|
||||
|
||||
@@ -43,8 +43,6 @@ pub async fn main() -> AnyhowResult<()> {
|
||||
let region_name = easyenv::get_env_string_required("REGION_NAME")?;
|
||||
let public_bucket_name = easyenv::get_env_string_required("PUBLIC_BUCKET_NAME")?;
|
||||
|
||||
let s3_compatible_endpoint_url = easyenv::get_env_string_or_default(
|
||||
"S3_COMPATIBLE_ENDPOINT_URL", "");
|
||||
let bucket_timeout = easyenv::get_env_duration_seconds_or_default(
|
||||
"BUCKET_TIMEOUT_SECONDS", Duration::from_secs(60 * 5));
|
||||
|
||||
@@ -55,7 +53,6 @@ pub async fn main() -> AnyhowResult<()> {
|
||||
&secret_key,
|
||||
®ion_name,
|
||||
&public_bucket_name,
|
||||
&s3_compatible_endpoint_url,
|
||||
None,
|
||||
Some(bucket_timeout),
|
||||
)?;
|
||||
|
||||
@@ -26,4 +26,4 @@ my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
|
||||
# External
|
||||
clap = "4.4.8"
|
||||
tokio = { version = "1.38.0", features = ["macros"] }
|
||||
tokio = { version = "1.34.0", features = ["macros"] }
|
||||
|
||||
@@ -16,9 +16,10 @@ path = "src/main.rs"
|
||||
normal = ["my-workspace-hack"]
|
||||
|
||||
[dependencies]
|
||||
|
||||
# Internal
|
||||
container_common = { path = "../../../lib/deprecated/container_common" }
|
||||
easyenv = { path = "../../../lib/easyenv" }
|
||||
errors = { path = "../../../lib/errors" }
|
||||
|
||||
# Workspace hack (faster compile times)
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use log::info;
|
||||
|
||||
use container_common::anyhow_result::AnyhowResult;
|
||||
use easyenv::init_all_with_default_logging;
|
||||
use errors::AnyhowResult;
|
||||
|
||||
fn main() -> AnyhowResult<()> {
|
||||
init_all_with_default_logging(None);
|
||||
|
||||
@@ -18,6 +18,7 @@ normal = ["my-workspace-hack"]
|
||||
[dependencies]
|
||||
# Internal
|
||||
buckets = { path = "../../../_types/buckets" }
|
||||
container_common = { path = "../../../lib/deprecated/container_common" }
|
||||
easyenv = { path = "../../../lib/easyenv" }
|
||||
enums = { path = "../../../_types/enums" }
|
||||
errors = { path = "../../../lib/errors" }
|
||||
@@ -31,11 +32,11 @@ my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
# External
|
||||
clap = "4.4.8"
|
||||
dotenv = "0.15.0"
|
||||
itertools = "0.13.0"
|
||||
itertools = "0.11.0"
|
||||
log = "0.4.14"
|
||||
|
||||
# Bigger pieces
|
||||
tokio = { version = "1.38.0", features = ["macros"] }
|
||||
tokio = { version = "1.34.0", features = ["macros"] }
|
||||
sqlx = { version = "0.7.2", features = [ "mysql", "runtime-tokio", "tls-rustls", "chrono" ] }
|
||||
|
||||
# Serialization
|
||||
|
||||
@@ -2,8 +2,8 @@ use log::info;
|
||||
use sqlx::{MySql, Pool};
|
||||
use sqlx::mysql::MySqlPoolOptions;
|
||||
|
||||
use container_common::anyhow_result::AnyhowResult;
|
||||
use easyenv::init_all_with_default_logging;
|
||||
use errors::AnyhowResult;
|
||||
|
||||
use crate::cli_args::Action;
|
||||
use crate::operations::delete_all_anonymous_user_images::delete_all_anonymous_user_images::delete_all_anonymous_user_images;
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ use sqlx::{MySql, Pool};
|
||||
use enums::by_table::media_files::media_file_type::MediaFileType;
|
||||
use enums::common::view_as::ViewAs;
|
||||
use errors::AnyhowResult;
|
||||
use mysql_queries::queries::media_files::delete::delete_media_file::delete_media_file_as_mod;
|
||||
use mysql_queries::queries::media_files::delete_media_file::delete_media_file_as_mod;
|
||||
use mysql_queries::queries::media_files::list::list_media_files::{list_media_files, ListMediaFilesArgs};
|
||||
|
||||
use crate::cli_args::Args;
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ use sqlx::{MySql, Pool};
|
||||
|
||||
use enums::common::view_as::ViewAs;
|
||||
use errors::{anyhow, AnyhowResult};
|
||||
use mysql_queries::queries::media_files::delete::delete_media_file::delete_media_file_as_mod;
|
||||
use mysql_queries::queries::media_files::delete_media_file::delete_media_file_as_mod;
|
||||
use mysql_queries::queries::media_files::list::list_media_files_for_user::{list_media_files_for_user, ListMediaFileForUserArgs};
|
||||
use mysql_queries::queries::users::user_profiles::get_user_profile_by_username::get_user_profile_by_username;
|
||||
|
||||
|
||||
@@ -33,10 +33,10 @@ my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
# External
|
||||
clap = "4.4.8"
|
||||
log = "0.4.14"
|
||||
strum = { version = "0.26", features = ["derive"] }
|
||||
strum = { version = "0.25", features = ["derive"] }
|
||||
|
||||
# Bigger pieces
|
||||
tokio = { version = "1.38.0", features = ["macros"] }
|
||||
tokio = { version = "1.34.0", features = ["macros"] }
|
||||
sqlx = { version = "0.7.2", features = [ "mysql", "runtime-tokio", "tls-rustls", "chrono" ] }
|
||||
elasticsearch = "8.5.0-alpha.1"
|
||||
|
||||
|
||||
@@ -23,17 +23,10 @@ pub enum Environment {
|
||||
pub enum Action {
|
||||
ReindexTts,
|
||||
SearchTts,
|
||||
|
||||
/// Reindex model_weights into ElasticSearch
|
||||
ReindexModelWeights,
|
||||
|
||||
/// Search the model weights
|
||||
SearchModelWeights,
|
||||
|
||||
/// Reindex media_files into ElasticSearch
|
||||
/// For now, this is just media files that are relevant to the engine.
|
||||
ReindexMediaFiles,
|
||||
SearchMediaFiles,
|
||||
}
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
|
||||
@@ -20,8 +20,6 @@ use errors::AnyhowResult;
|
||||
use crate::cli_args::{Action, Environment, parse_cli_args};
|
||||
use crate::plans::create_all_model_weight_documents::create_all_model_weight_documents;
|
||||
use crate::plans::create_all_tts_documents::create_all_tts_documents;
|
||||
use crate::plans::media_files::create_dimensional_media_file_documents::create_dimensional_media_file_documents;
|
||||
use crate::plans::media_files::test_search_media_files_documents::test_search_media_files;
|
||||
|
||||
pub mod cli_args;
|
||||
pub mod plans;
|
||||
@@ -64,14 +62,6 @@ pub async fn main() -> AnyhowResult<()> {
|
||||
println!("Result: {:#?}", result);
|
||||
}
|
||||
}
|
||||
Action::ReindexMediaFiles => {
|
||||
info!("Reindexing media files...");
|
||||
create_dimensional_media_file_documents(&mysql, &elasticsearch).await?;
|
||||
}
|
||||
Action::SearchMediaFiles => {
|
||||
info!("Search media files...");
|
||||
test_search_media_files(&elasticsearch).await?;
|
||||
}
|
||||
}
|
||||
|
||||
info!("Done!");
|
||||
|
||||
+2
-7
@@ -13,11 +13,7 @@ use errors::AnyhowResult;
|
||||
use mysql_queries::queries::model_weights::list::list_model_weights_for_elastic_search_backfill_using_cursor::{list_model_weights_for_elastic_search_backfill_using_cursor, ModelWeightForElasticsearchRecord};
|
||||
use storyteller_root::get_storyteller_rust_root;
|
||||
|
||||
pub async fn create_all_model_weight_documents(
|
||||
mysql: &Pool<MySql>,
|
||||
elasticsearch: &Elasticsearch
|
||||
) -> AnyhowResult<()> {
|
||||
|
||||
pub async fn create_all_model_weight_documents(mysql: &Pool<MySql>, elasticsearch: &Elasticsearch) -> AnyhowResult<()> {
|
||||
info!("Create all model weight documents.");
|
||||
|
||||
// TODO(bt, 2024-01-10): expose this as a CLI flag
|
||||
@@ -67,8 +63,7 @@ async fn create_document_from_record(elasticsearch: &Elasticsearch, record: Mode
|
||||
weights_type: record.weights_type,
|
||||
weights_category: record.weights_category,
|
||||
|
||||
title: record.title.clone(),
|
||||
title_as_keyword: record.title,
|
||||
title: record.title,
|
||||
|
||||
maybe_cover_image_media_file_token: record.maybe_cover_image_media_file_token,
|
||||
maybe_cover_image_public_bucket_hash: record.maybe_cover_image_public_bucket_hash,
|
||||
|
||||
-190
@@ -1,190 +0,0 @@
|
||||
use std::collections::HashSet;
|
||||
use std::fs::read_to_string;
|
||||
use std::iter::FromIterator;
|
||||
|
||||
use elasticsearch::{BulkOperation, BulkParts, Elasticsearch};
|
||||
use log::{error, info, warn};
|
||||
use serde_json::Value;
|
||||
use sqlx::{MySql, Pool};
|
||||
|
||||
use elasticsearch_schema::documents::media_file_document::{MEDIA_FILE_INDEX, MediaFileDocument};
|
||||
use elasticsearch_schema::traits::document::Document;
|
||||
use elasticsearch_schema::utils::create_index_if_not_exists::{create_index_if_not_exists, CreateIndexArgs};
|
||||
use enums::by_table::media_files::media_file_class::MediaFileClass;
|
||||
use enums::by_table::media_files::media_file_engine_category::MediaFileEngineCategory;
|
||||
use enums::by_table::media_files::media_file_type::MediaFileType;
|
||||
use errors::AnyhowResult;
|
||||
use mysql_queries::queries::media_files::list::list_media_files_for_elastic_search_backfill_using_cursor::{list_media_files_for_elastic_search_backfill_using_cursor, ListArgs, MediaFileForElasticsearchRecord};
|
||||
use mysql_queries::queries::model_weights::list::list_model_weights_for_elastic_search_backfill_using_cursor::{list_model_weights_for_elastic_search_backfill_using_cursor, ModelWeightForElasticsearchRecord};
|
||||
use storyteller_root::get_storyteller_rust_root;
|
||||
|
||||
pub async fn create_dimensional_media_file_documents(
|
||||
mysql: &Pool<MySql>,
|
||||
elasticsearch: &Elasticsearch
|
||||
) -> AnyhowResult<()> {
|
||||
|
||||
info!("Create dimensional media file documents.");
|
||||
|
||||
// TODO(bt, 2024-01-10): expose this as a CLI flag
|
||||
const DELETE_EXISTING_INDEX : bool = true;
|
||||
const PAGE_SIZE : usize = 1000;
|
||||
|
||||
create_media_file_index(&elasticsearch, DELETE_EXISTING_INDEX).await?;
|
||||
|
||||
let mut cursor = 0;
|
||||
|
||||
loop {
|
||||
info!("Cursor: {cursor}");
|
||||
|
||||
let results = list_media_files_for_elastic_search_backfill_using_cursor(ListArgs {
|
||||
mysql_pool: mysql,
|
||||
page_size: PAGE_SIZE,
|
||||
cursor,
|
||||
maybe_filter_engine_categories: Some(&HashSet::from_iter(vec![
|
||||
MediaFileEngineCategory::Animation,
|
||||
MediaFileEngineCategory::Character,
|
||||
MediaFileEngineCategory::Creature,
|
||||
MediaFileEngineCategory::Expression,
|
||||
MediaFileEngineCategory::ImagePlane,
|
||||
MediaFileEngineCategory::Location,
|
||||
MediaFileEngineCategory::Object,
|
||||
MediaFileEngineCategory::Scene,
|
||||
MediaFileEngineCategory::SetDressing,
|
||||
MediaFileEngineCategory::Skybox,
|
||||
MediaFileEngineCategory::VideoPlane,
|
||||
])),
|
||||
maybe_filter_media_types: Some(&HashSet::from_iter(vec![
|
||||
// Engine types
|
||||
MediaFileType::Csv,
|
||||
MediaFileType::Fbx,
|
||||
MediaFileType::Glb,
|
||||
MediaFileType::SceneJson,
|
||||
// Image types
|
||||
MediaFileType::Gif,
|
||||
MediaFileType::Jpg,
|
||||
MediaFileType::Png,
|
||||
])),
|
||||
maybe_filter_media_classes: Some(&HashSet::from_iter(vec![
|
||||
MediaFileClass::Image,
|
||||
MediaFileClass::Dimensional,
|
||||
])),
|
||||
}).await?;
|
||||
|
||||
info!("Results length: {}", results.len());
|
||||
|
||||
if results.is_empty() {
|
||||
info!("No more results at cursor {cursor}");
|
||||
break;
|
||||
}
|
||||
|
||||
let maybe_last_id = results.last().map(|result| result.id);
|
||||
|
||||
match maybe_last_id {
|
||||
Some(last_id) => cursor = last_id as usize,
|
||||
None => {
|
||||
warn!("No final ID at cursor {cursor}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for result in results {
|
||||
create_document_from_record(elasticsearch, result).await?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn create_document_from_record(elasticsearch: &Elasticsearch, record: MediaFileForElasticsearchRecord) -> AnyhowResult<()> {
|
||||
info!("Create record for {:?}", record.token);
|
||||
|
||||
let is_deleted = record.user_deleted_at.is_some() || record.mod_deleted_at.is_some();
|
||||
|
||||
let document = MediaFileDocument {
|
||||
token: record.token,
|
||||
|
||||
media_class: record.media_class,
|
||||
media_type: record.media_type,
|
||||
maybe_media_subtype: record.maybe_media_subtype,
|
||||
maybe_engine_category: record.maybe_engine_category,
|
||||
maybe_animation_type: record.maybe_animation_type,
|
||||
|
||||
maybe_mime_type: record.maybe_mime_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,
|
||||
creator_set_visibility: record.creator_set_visibility,
|
||||
|
||||
maybe_title: record.maybe_title.clone(),
|
||||
maybe_title_as_keyword: record.maybe_title,
|
||||
|
||||
maybe_cover_image_media_file_token: record.maybe_cover_image_media_file_token,
|
||||
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_creator_user_token: record.maybe_creator_user_token,
|
||||
maybe_creator_username: record.maybe_creator_username,
|
||||
maybe_creator_display_name: record.maybe_creator_display_name,
|
||||
maybe_creator_gravatar_hash: record.maybe_creator_gravatar_hash,
|
||||
|
||||
is_featured: record.is_featured,
|
||||
|
||||
created_at: record.created_at,
|
||||
updated_at: record.updated_at,
|
||||
user_deleted_at: record.user_deleted_at,
|
||||
mod_deleted_at: record.mod_deleted_at,
|
||||
|
||||
is_deleted,
|
||||
};
|
||||
|
||||
let op : BulkOperation<_> = BulkOperation::index(&document)
|
||||
.id(document.get_document_id())
|
||||
.into();
|
||||
|
||||
let response = elasticsearch
|
||||
.bulk(BulkParts::Index(MEDIA_FILE_INDEX))
|
||||
.body(vec![op])
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
let json: Value = response.json().await?;
|
||||
|
||||
let had_errors = json["errors"].as_bool().unwrap_or(false);
|
||||
|
||||
if had_errors {
|
||||
let failed: Vec<&Value> = json["items"]
|
||||
.as_array()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.filter(|v| !v["error"].is_null())
|
||||
.collect();
|
||||
|
||||
// TODO: retry failures
|
||||
error!("Errors during indexing. Failures: {}", failed.len());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// NB: Adapted from elasticsearch crate examples source
|
||||
async fn create_media_file_index(client: &Elasticsearch, delete_existing: bool) -> AnyhowResult<()> {
|
||||
|
||||
info!("Creating model media file index...");
|
||||
|
||||
let index_path = get_storyteller_rust_root()
|
||||
.join("_elasticsearch/index_definitions/media_files_v1.json");
|
||||
|
||||
info!("Reading index file: {:?}", index_path);
|
||||
|
||||
let index_definition = read_to_string(index_path)?;
|
||||
|
||||
create_index_if_not_exists(CreateIndexArgs {
|
||||
client,
|
||||
index_name: MEDIA_FILE_INDEX,
|
||||
index_definition: &index_definition,
|
||||
delete_existing,
|
||||
}).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
pub mod create_dimensional_media_file_documents;
|
||||
pub mod test_search_media_files_documents;
|
||||
-30
@@ -1,30 +0,0 @@
|
||||
use std::collections::HashSet;
|
||||
use std::iter::FromIterator;
|
||||
|
||||
use elasticsearch::Elasticsearch;
|
||||
|
||||
use elasticsearch_schema::searches::search_media_files::{search_media_files, SearchArgs};
|
||||
use enums::by_table::media_files::media_file_class::MediaFileClass;
|
||||
use errors::AnyhowResult;
|
||||
|
||||
pub async fn test_search_media_files(client: &Elasticsearch) -> AnyhowResult<()> {
|
||||
|
||||
let results = search_media_files(SearchArgs {
|
||||
search_term: "cac",
|
||||
is_featured: None,
|
||||
maybe_creator_user_token: None,
|
||||
maybe_media_classes: Some(HashSet::from_iter(vec![
|
||||
MediaFileClass::Dimensional,
|
||||
MediaFileClass::Image,
|
||||
])),
|
||||
maybe_media_types: None,
|
||||
maybe_engine_categories: None,
|
||||
client,
|
||||
}).await?;
|
||||
|
||||
for result in results {
|
||||
println!("Result: {:#?}", result);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,3 +1,2 @@
|
||||
pub mod create_all_model_weight_documents;
|
||||
pub mod create_all_tts_documents;
|
||||
pub mod media_files;
|
||||
pub mod create_all_tts_documents;
|
||||
@@ -35,11 +35,11 @@ my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
# External
|
||||
clap = "4.4.8"
|
||||
log = "0.4.14"
|
||||
strum = { version = "0.26", features = ["derive"] }
|
||||
strum = { version = "0.25", features = ["derive"] }
|
||||
tempdir = "0.3.7"
|
||||
|
||||
# Async + clients
|
||||
tokio = { version = "1.38.0", features = ["macros"] }
|
||||
tokio = { version = "1.34.0", features = ["macros"] }
|
||||
sqlx = { version = "0.7.2", features = [ "mysql", "runtime-tokio", "tls-rustls", "chrono" ] }
|
||||
|
||||
# Serialization
|
||||
|
||||
@@ -75,8 +75,6 @@ pub fn get_bucket_client(env_var_suffix: &str) -> AnyhowResult<BucketClient> {
|
||||
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}"))?;
|
||||
|
||||
let s3_compatible_endpoint_url = easyenv::get_env_string_or_default(
|
||||
&format!("S3_COMPATIBLE_ENDPOINT_URL_{env_var_suffix}"), "https://storage.googleapis.com");
|
||||
// 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(
|
||||
@@ -89,7 +87,6 @@ pub fn get_bucket_client(env_var_suffix: &str) -> AnyhowResult<BucketClient> {
|
||||
&secret_key,
|
||||
®ion_name,
|
||||
&bucket_name,
|
||||
&s3_compatible_endpoint_url,
|
||||
None,
|
||||
Some(bucket_timeout),
|
||||
)?)
|
||||
|
||||
@@ -29,10 +29,10 @@ log = "0.4.14"
|
||||
|
||||
# Actix
|
||||
actix-cors = "0.6.4"
|
||||
actix-http = "3.7.0"
|
||||
actix-web = "4.7.0"
|
||||
actix-http = "3.4.0"
|
||||
actix-web = "4.4.0"
|
||||
url = { version = "2.5.0", features = [] }
|
||||
|
||||
[dev-dependencies]
|
||||
actix-rt = "2.10.0"
|
||||
actix-rt = "2.9.0"
|
||||
speculoos = "0.11.0" # Fluent assertions
|
||||
|
||||
+7
-32
@@ -2,17 +2,14 @@ use actix_cors::Cors;
|
||||
|
||||
use crate::util::netlify_branch_domain_matches::netlify_branch_domain_matches;
|
||||
|
||||
pub fn add_storyteller_studio(cors: Cors, _is_production: bool) -> Cors {
|
||||
cors.allowed_origin("https://studio.storyteller.ai")
|
||||
.allowed_origin("https://studio-staging.studio.storyteller.ai")
|
||||
.allowed_origin("https://studio-testing.studio.storyteller.ai")
|
||||
.allowed_origin_fn(|origin, _req_head| {
|
||||
netlify_branch_domain_matches(origin, "storytellerstudio.netlify.app")
|
||||
})
|
||||
pub fn add_gotta_go_fast_test_branches(cors: Cors, _is_production: bool) -> Cors {
|
||||
cors.allowed_origin("http://localhost:5173")
|
||||
.allowed_origin_fn(|origin, _req_head| {
|
||||
netlify_branch_domain_matches(origin, "pipeline-gottagofast.netlify.app")
|
||||
})
|
||||
.allowed_origin("http://localhost:5173")
|
||||
.allowed_origin_fn(|origin, _req_head| {
|
||||
netlify_branch_domain_matches(origin, "storytellerstudio.netlify.app")
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -56,40 +53,18 @@ mod tests {
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn studio_main() {
|
||||
let production_cors = build_cors_config(ServerEnvironment::Production);
|
||||
assert_origin_ok(&production_cors, "https://studio.storyteller.ai").await;
|
||||
assert_origin_invalid(&production_cors, "https://studiofake.storyteller.ai").await;
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn studio_staging() {
|
||||
let production_cors = build_cors_config(ServerEnvironment::Production);
|
||||
assert_origin_ok(&production_cors, "https://studio-staging.studio.storyteller.ai").await;
|
||||
assert_origin_invalid(&production_cors, "https://studio-staging-fake.studio.storyteller.ai").await;
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn studio_testing() {
|
||||
let production_cors = build_cors_config(ServerEnvironment::Production);
|
||||
assert_origin_ok(&production_cors, "https://studio-testing.studio.storyteller.ai").await;
|
||||
assert_origin_invalid(&production_cors, "https://studio-testing-fake.studio.storyteller.ai").await;
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn studio_netlify() {
|
||||
let production_cors = build_cors_config(ServerEnvironment::Production);
|
||||
assert_origin_ok(&production_cors, "https://storytellerstudio.netlify.app").await;
|
||||
assert_origin_invalid(&production_cors, "https://storytellerstudiofake.netlify.app").await;
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn studio_netlify_branch_deploy() {
|
||||
async fn studio_branch_deploy() {
|
||||
let production_cors = build_cors_config(ServerEnvironment::Production);
|
||||
assert_origin_ok(&production_cors, "https://foo--storytellerstudio.netlify.app").await;
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn studio_netlify_deploy_preview() {
|
||||
async fn studio_deploy_preview() {
|
||||
let production_cors = build_cors_config(ServerEnvironment::Production);
|
||||
assert_origin_ok(&production_cors, "https://deploy-preview-123--storytellerstudio.netlify.app").await;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
pub (crate) mod development_only;
|
||||
pub (crate) mod fakeyou;
|
||||
pub (crate) mod storyteller_studio;
|
||||
pub (crate) mod gottagofast;
|
||||
pub (crate) mod legacy;
|
||||
pub (crate) mod storyteller;
|
||||
@@ -5,7 +5,7 @@ use reusable_types::server_environment::ServerEnvironment;
|
||||
|
||||
use crate::configs::development_only::add_development_only;
|
||||
use crate::configs::fakeyou::{add_fakeyou, add_fakeyou_dev_proxy};
|
||||
use crate::configs::storyteller_studio::add_storyteller_studio;
|
||||
use crate::configs::gottagofast::add_gotta_go_fast_test_branches;
|
||||
use crate::configs::legacy::{add_legacy_storyteller_stream, add_legacy_trumped, add_legacy_vocodes, add_power_stream};
|
||||
use crate::configs::storyteller::{add_storyteller, add_storyteller_dev_proxy};
|
||||
|
||||
@@ -34,7 +34,7 @@ fn do_build_cors_config(is_production: bool) -> Cors {
|
||||
cors = add_fakeyou_dev_proxy(cors, is_production);
|
||||
cors = add_storyteller(cors, is_production);
|
||||
cors = add_storyteller_dev_proxy(cors, is_production);
|
||||
cors = add_storyteller_studio(cors, is_production);
|
||||
cors = add_gotta_go_fast_test_branches(cors, is_production);
|
||||
|
||||
// Legacy
|
||||
cors = add_legacy_trumped(cors, is_production);
|
||||
|
||||
@@ -24,11 +24,11 @@ errors = { path = "../../lib/errors" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
# Actix
|
||||
actix-http = "3.7.0"
|
||||
actix-rt = "2.10.0"
|
||||
actix-http = "3.4.0"
|
||||
actix-rt = "2.9.0"
|
||||
actix-service = "2.0.2"
|
||||
actix-utils = "3.0.1"
|
||||
actix-web = "4.7.0"
|
||||
actix-web = "4.4.0"
|
||||
|
||||
# IPv4 and v6 CIDRs (crate has few dependencies)
|
||||
cidr-utils = "0.5.11"
|
||||
|
||||
@@ -32,13 +32,13 @@ my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
# External
|
||||
anyhow = "1.0.86"
|
||||
log = "0.4.14"
|
||||
env_logger = "0.11.3"
|
||||
env_logger = "0.10.1"
|
||||
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.34.0" }
|
||||
rust-s3 = { version = "0.33.0" }
|
||||
|
||||
# Runtime
|
||||
# NB: We switched to Tokio from `async-std` for broader ecosystem support.
|
||||
tokio = { version = "1.38.0", features = ["macros"] }
|
||||
tokio = { version = "1.34.0", features = ["macros"] }
|
||||
|
||||
|
||||
@@ -47,7 +47,6 @@ impl BucketClient {
|
||||
secret_key: &str,
|
||||
region_name: &str,
|
||||
bucket_name: &str,
|
||||
s3_endpoint: &str,
|
||||
optional_bucket_root: Option<&str>,
|
||||
// See underlying docs for timeout details.
|
||||
bucket_request_timeout: Option<Duration>,
|
||||
@@ -64,14 +63,14 @@ impl BucketClient {
|
||||
// NB: The GCS buckets aren't supported by default.
|
||||
let region = Region::Custom {
|
||||
region: region_name.to_owned(),
|
||||
endpoint: s3_endpoint.to_owned(),
|
||||
endpoint: "https://storage.googleapis.com".to_owned(),
|
||||
};
|
||||
|
||||
let mut bucket = Bucket::new(&bucket_name, region, credentials)?;
|
||||
|
||||
bucket.set_request_timeout(bucket_request_timeout);
|
||||
bucket.set_path_style();
|
||||
// bucket.set_subdomain_style();
|
||||
bucket.set_subdomain_style();
|
||||
|
||||
let optional_bucket_root = optional_bucket_root.map(|s| s.to_string());
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ pub struct BucketOrchestration {
|
||||
region_name: String,
|
||||
public_bucket_name: String,
|
||||
private_bucket_name: String,
|
||||
s3_compatible_endpoint_url: String,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
@@ -64,17 +63,12 @@ impl BucketOrchestration {
|
||||
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 s3_compatible_endpoint_url = easyenv::get_env_string_or_default(
|
||||
"S3_COMPATIBLE_ENDPOINT_URL",
|
||||
"https://storage.googleapis.com",
|
||||
);
|
||||
|
||||
|
||||
let bucket_orchestration = BucketOrchestration::new(
|
||||
access_key,
|
||||
secret_key,
|
||||
region_name,
|
||||
s3_compatible_endpoint_url,
|
||||
public_bucket_name,
|
||||
private_bucket_name,
|
||||
);
|
||||
@@ -86,7 +80,6 @@ impl BucketOrchestration {
|
||||
access_key: String,
|
||||
secret_key: String,
|
||||
region_name: String,
|
||||
s3_compatible_endpoint_url: String,
|
||||
public_bucket_name: String,
|
||||
private_bucket_name: String) -> Self {
|
||||
Self {
|
||||
@@ -95,7 +88,6 @@ impl BucketOrchestration {
|
||||
region_name,
|
||||
public_bucket_name,
|
||||
private_bucket_name,
|
||||
s3_compatible_endpoint_url,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,7 +102,6 @@ impl BucketOrchestration {
|
||||
&self.access_key,
|
||||
&self.secret_key,
|
||||
&self.region_name,
|
||||
&self.s3_compatible_endpoint_url,
|
||||
&self.public_bucket_name,
|
||||
None,
|
||||
Some(bucket_timeout),
|
||||
@@ -121,7 +112,6 @@ impl BucketOrchestration {
|
||||
&self.access_key,
|
||||
&self.secret_key,
|
||||
&self.region_name,
|
||||
&self.s3_compatible_endpoint_url,
|
||||
&self.private_bucket_name,
|
||||
None,
|
||||
Some(bucket_timeout),
|
||||
|
||||
@@ -15,5 +15,5 @@ my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
# External
|
||||
easyenv = { path = "../../easyenv" }
|
||||
log = "0.4.20"
|
||||
reqwest = "0.12.4"
|
||||
reqwest = "0.11.24"
|
||||
serde_json = "1.0.113"
|
||||
|
||||
@@ -1,62 +1,6 @@
|
||||
use log::error;
|
||||
use serde_json::{json, Value};
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ThumbnailTaskInputMimeType {
|
||||
MP4
|
||||
}
|
||||
|
||||
pub enum ThumbnailTaskOutputMimeType {
|
||||
PNG,
|
||||
JPEG,
|
||||
GIF,
|
||||
}
|
||||
|
||||
impl ThumbnailTaskInputMimeType {
|
||||
fn as_str(&self) -> &str {
|
||||
match self {
|
||||
ThumbnailTaskInputMimeType::MP4 => "video/mp4",
|
||||
}
|
||||
}
|
||||
|
||||
fn as_string(&self) -> String {
|
||||
self.as_str().to_string()
|
||||
}
|
||||
|
||||
fn to_output_mimetypes(&self) -> Vec<ThumbnailTaskOutputMimeType> {
|
||||
match self {
|
||||
ThumbnailTaskInputMimeType::MP4 => vec![
|
||||
ThumbnailTaskOutputMimeType::JPEG,
|
||||
ThumbnailTaskOutputMimeType::GIF,
|
||||
],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ThumbnailTaskOutputMimeType {
|
||||
fn as_str(&self) -> &str {
|
||||
match self {
|
||||
ThumbnailTaskOutputMimeType::PNG => "image/png",
|
||||
ThumbnailTaskOutputMimeType::JPEG => "image/jpeg",
|
||||
ThumbnailTaskOutputMimeType::GIF => "image/gif",
|
||||
}
|
||||
}
|
||||
|
||||
fn as_string(&self) -> String {
|
||||
self.as_str().to_string()
|
||||
}
|
||||
|
||||
fn to_extension(&self) -> &str {
|
||||
match self {
|
||||
ThumbnailTaskOutputMimeType::PNG => "png",
|
||||
ThumbnailTaskOutputMimeType::JPEG => "jpg",
|
||||
ThumbnailTaskOutputMimeType::GIF => "gif",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ThumbnailTaskError {
|
||||
InvalidTask,
|
||||
@@ -75,20 +19,22 @@ struct ThumbnailTask{
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ThumbnailTaskBuilder{
|
||||
source_mimetype: ThumbnailTaskInputMimeType,
|
||||
bucket: Option<String>,
|
||||
path: Option<String>,
|
||||
source_mimetype: Option<String>,
|
||||
output_mimetype: Option<String>,
|
||||
output_extension: Option<String>,
|
||||
output_suffix: Option<String>,
|
||||
event_id: Option<String>,
|
||||
}
|
||||
|
||||
impl ThumbnailTaskBuilder {
|
||||
pub fn new_for_source_mimetype(source_mimetype: ThumbnailTaskInputMimeType) -> Self {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
source_mimetype,
|
||||
bucket: None,
|
||||
path: None,
|
||||
source_mimetype: None,
|
||||
output_mimetype: None,
|
||||
output_extension: None,
|
||||
output_suffix: None,
|
||||
event_id: None,
|
||||
@@ -105,6 +51,21 @@ impl ThumbnailTaskBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_source_mimetype(&mut self, source_mimetype: &str) -> &mut Self {
|
||||
self.source_mimetype = Some(source_mimetype.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_output_mimetype(&mut self, output_mimetype: &str) -> &mut Self {
|
||||
self.output_mimetype = Some(output_mimetype.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_output_extension(&mut self, output_extension: &str) -> &mut Self {
|
||||
self.output_extension = Some(output_extension.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_output_suffix(&mut self, output_suffix: &str) -> &mut Self {
|
||||
self.output_suffix = Some(output_suffix.to_string());
|
||||
self
|
||||
@@ -115,43 +76,30 @@ impl ThumbnailTaskBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
fn build(&self, thumbnail_task_output_mime_type: ThumbnailTaskOutputMimeType) -> Result<ThumbnailTask, String> {
|
||||
fn build(&self) -> Result<ThumbnailTask, String> {
|
||||
Ok(ThumbnailTask {
|
||||
source_mimetype: self.source_mimetype.as_string(),
|
||||
output_mimetype: thumbnail_task_output_mime_type.as_string(),
|
||||
output_extension: thumbnail_task_output_mime_type.to_extension().to_string(),
|
||||
bucket: self.bucket.clone().ok_or("bucket is required")?,
|
||||
path: self.path.clone().ok_or("path is required")?,
|
||||
source_mimetype: self.source_mimetype.clone().ok_or("source_mimetype is required")?,
|
||||
output_mimetype: self.output_mimetype.clone().ok_or("output_mimetype is required")?,
|
||||
output_extension: self.output_extension.clone().ok_or("output_extension is required")?,
|
||||
output_suffix: self.output_suffix.clone().unwrap_or("".to_string()),
|
||||
event_id: self.event_id.clone().ok_or("event_id is required")?,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn send_all(&self) -> Result<(), ThumbnailTaskError> {
|
||||
let mut results: Vec<Result<(), ThumbnailTaskError>> = vec![];
|
||||
for output_mimetype in self.source_mimetype.to_output_mimetypes() {
|
||||
match self.build(output_mimetype) {
|
||||
Ok(task) => {
|
||||
match task.send().await {
|
||||
Ok(_) => {},
|
||||
Err(err) => {
|
||||
error!("Failed to send thumbnail task: {:?} with err {:?}", self, err);
|
||||
results.push(Err(ThumbnailTaskError::RequestError));
|
||||
},
|
||||
}
|
||||
pub async fn send(&self) -> Result<(), ThumbnailTaskError> {
|
||||
match self.build() {
|
||||
Ok(task) => {
|
||||
match task.send().await {
|
||||
Ok(_) => Ok(()),
|
||||
Err(_) => Err(ThumbnailTaskError::RequestError),
|
||||
}
|
||||
Err(err) => {
|
||||
error!("Invalid thumbnail task: {:?} with err {:?}", self, err);
|
||||
results.push(Err(ThumbnailTaskError::InvalidTask));
|
||||
},
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
if results.iter().any(|r| r.is_err()) {
|
||||
Err(ThumbnailTaskError::RequestError)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
Err(_) => {
|
||||
error!("Invalid thumbnail task: {:?}", self);
|
||||
Err(ThumbnailTaskError::InvalidTask)
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -195,15 +143,9 @@ impl ThumbnailTask{
|
||||
"http://media-server.thumbnail-generator/tasks",
|
||||
);
|
||||
|
||||
let basic_auth = easyenv::get_env_string_or_default(
|
||||
"THUMBNAIL_GENERATOR_API_BASIC_AUTH",
|
||||
"",
|
||||
);
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let task_json = self.request_json();
|
||||
client.post(url)
|
||||
.header("Authorization", "Basic ".to_owned() + &basic_auth)
|
||||
.json(&task_json)
|
||||
.send()
|
||||
.await?
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
[package]
|
||||
name = "twitch_common"
|
||||
edition = "2018"
|
||||
version = "0.0.1"
|
||||
authors = [
|
||||
"Brandon Thomas <bt@brand.io>",
|
||||
"Brandon Thomas <echelon@gmail.com>",
|
||||
]
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
name = "twitch_common"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[package.metadata.cargo-udeps.ignore]
|
||||
normal = ["my-workspace-hack"]
|
||||
|
||||
[dependencies]
|
||||
|
||||
# Internal
|
||||
container_common = { path = "../../deprecated/container_common" }
|
||||
easyenv = { path = "../../easyenv" }
|
||||
|
||||
# Workspace hack (faster compile times)
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
|
||||
# External
|
||||
anyhow = "1.0.86"
|
||||
once_cell = "1.18.0"
|
||||
regex = "1.5.4"
|
||||
|
||||
# Twitch
|
||||
# NB "unsupported" pubsub features may disappear from the Twitch API at any time. It's an unofficial API.
|
||||
# twitch_api2 = { version = "0.6.0-rc.2", features = ["helix", "reqwest_client", "pubsub", "chrono", "unsupported"] }
|
||||
twitch_oauth2 = "0.6.0-rc.2"
|
||||
|
||||
# Serialization
|
||||
serde = "1.0.125"
|
||||
serde_derive = "1.0.125"
|
||||
@@ -0,0 +1,107 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
use once_cell::sync::Lazy;
|
||||
use regex::Regex;
|
||||
|
||||
// NB: This can be used as a nice, succinct macro with once_cell:
|
||||
//macro_rules! regex {
|
||||
// ($re:literal $(,)?) => {{
|
||||
// static RE: once_cell::sync::OnceCell<regex::Regex> = once_cell::sync::OnceCell::new();
|
||||
// RE.get_or_init(|| regex::Regex::new($re).unwrap())
|
||||
// }};
|
||||
//}
|
||||
|
||||
/// Remove cheermotes from text, eg "this is great Cheer1" -> "this is great"
|
||||
pub fn remove_cheers(text: &str) -> String {
|
||||
let result = TWITCH_CHEER_REGEX.replace_all(text, "");
|
||||
let result = MULTI_SPACE_REGEX.replace_all(&result, " ").to_string();
|
||||
result.trim().to_string()
|
||||
}
|
||||
|
||||
/// These cheer emotes always combine with a number
|
||||
/// This list seems pretty comprehensive
|
||||
/// https://github.com/nossebro/TwitchPubSubMirror/blob/master/TwitchPubSubMirror_StreamlabsSystem.py
|
||||
|
||||
static TWITCH_CHEERS : Lazy<HashSet<String>> = Lazy::new(|| {
|
||||
let cheers = vec![
|
||||
"Cheer",
|
||||
"DoodleCheer",
|
||||
"BibleThump",
|
||||
"cheerwhal",
|
||||
"Corgo",
|
||||
"uni",
|
||||
"ShowLove",
|
||||
"Party",
|
||||
"SeemsGood",
|
||||
"Pride",
|
||||
"Kappa",
|
||||
"FrankerZ",
|
||||
"HeyGuys",
|
||||
"DansGame",
|
||||
"EleGiggle",
|
||||
"TriHard",
|
||||
"Kreygasm",
|
||||
"4Head",
|
||||
"SwiftRage",
|
||||
"NotLikeThis",
|
||||
"FailFish",
|
||||
"VoHiYo",
|
||||
"PJSalt",
|
||||
"MrDestructoid",
|
||||
"bday",
|
||||
"RIPCheer",
|
||||
"Shamrock",
|
||||
"BitBoss",
|
||||
"Streamlabs",
|
||||
"Muxy",
|
||||
"HolidayCheer"
|
||||
];
|
||||
let mut s = HashSet::new();
|
||||
for cheer in cheers.into_iter() {
|
||||
s.insert(cheer.to_string());
|
||||
}
|
||||
s
|
||||
});
|
||||
|
||||
static MULTI_SPACE_REGEX : Lazy<Regex> = Lazy::new(|| {
|
||||
Regex::new("(\\s{2,})").unwrap()
|
||||
});
|
||||
|
||||
static TWITCH_CHEER_REGEX : Lazy<Regex> = Lazy::new(|| {
|
||||
let mut regex_pieces = Vec::new();
|
||||
|
||||
for cheer in TWITCH_CHEERS.iter() {
|
||||
regex_pieces.push(format!("({}\\d+)", cheer));
|
||||
}
|
||||
|
||||
let regex = regex_pieces.join("|");
|
||||
|
||||
// NB: (?i) is case insensitive search
|
||||
// https://docs.rs/regex/1.5.4/regex/#structs
|
||||
let regex = format!("(?i)({})", regex);
|
||||
|
||||
Regex::new(®ex).unwrap()
|
||||
});
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::cheers::remove_cheers;
|
||||
|
||||
#[test]
|
||||
fn test_remove_cheers() {
|
||||
let r = remove_cheers("testing Kappa1 SeemsGood100 removal");
|
||||
assert_eq!(&r, "testing removal");
|
||||
|
||||
let r = remove_cheers("Kappa1 SeemsGood100 no more Cheer1 cheers");
|
||||
assert_eq!(&r, "no more cheers");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_remove_cheers_case_insensitive() {
|
||||
let r = remove_cheers("testing cheer1");
|
||||
assert_eq!(&r, "testing");
|
||||
|
||||
let r = remove_cheers("TESTING CHEER1");
|
||||
assert_eq!(&r, "TESTING");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
pub mod cheers;
|
||||
pub mod oauth_token_builder;
|
||||
pub mod twitch_secrets;
|
||||
pub mod twitch_user_id;
|
||||
@@ -0,0 +1,66 @@
|
||||
use twitch_oauth2::{ClientId, ClientSecret, Scope};
|
||||
use twitch_oauth2::tokens::UserTokenBuilder;
|
||||
use twitch_oauth2::url::Url;
|
||||
|
||||
/// Get the token builder with the scopes our app needs
|
||||
/// This is used in several places, so centralize creation here.
|
||||
pub fn get_oauth_token_builder(
|
||||
client_id: &str,
|
||||
client_secret: &str,
|
||||
redirect_url: &Url,
|
||||
force_verify: bool
|
||||
) -> UserTokenBuilder {
|
||||
|
||||
let client_id = ClientId::new(client_id);
|
||||
let client_secret = ClientSecret::new(client_secret);
|
||||
|
||||
/*
|
||||
- AnalyticsReadExtensions, scope: "analytics:read:extensions", doc: "View analytics data for the Twitch Extensions owned by the authenticated account.";
|
||||
- AnalyticsReadGames, scope: "analytics:read:games", doc: "View analytics data for the games owned by the authenticated account.";
|
||||
[YES] BitsRead, scope: "bits:read", doc: "View Bits information for a channel.";
|
||||
- ChannelEditCommercial, scope: "channel:edit:commercial", doc: "Run commercials on a channel.";
|
||||
- ChannelManageBroadcast, scope: "channel:manage:broadcast", doc: "Manage a channel’s broadcast configuration, including updating channel configuration and managing stream markers and stream tags.";
|
||||
- ChannelManageExtensions, scope: "channel:manage:extensions", doc: "Manage a channel’s Extension configuration, including activating Extensions.";
|
||||
(?) ChannelManagePolls, scope: "channel:manage:polls", doc: "Manage a channel’s polls.";
|
||||
(?) ChannelManagePredictions, scope: "channel:manage:predictions", doc: "Manage of channel’s Channel Points Predictions";
|
||||
- ChannelManageRedemptions, scope: "channel:manage:redemptions", doc: "Manage Channel Points custom rewards and their redemptions on a channel.";
|
||||
- ChannelManageSchedule, scope: "channel:manage:schedule", doc: "Manage a channel’s stream schedule.";
|
||||
- ChannelManageVideos, scope: "channel:manage:videos", doc: "Manage a channel’s videos, including deleting videos.";
|
||||
- ChannelModerate, scope: "channel:moderate", doc: "Perform moderation actions in a channel. The user requesting the scope must be a moderator in the channel.";
|
||||
- ChannelReadEditors, scope: "channel:read:editors", doc: "View a list of users with the editor role for a channel.";
|
||||
- ChannelReadGoals, scope: "channel:read:goals", doc: "View Creator Goals for a channel.";
|
||||
- ChannelReadHypeTrain, scope: "channel:read:hype_train", doc: "View Hype Train information for a channel.";
|
||||
(?) ChannelReadPolls, scope: "channel:read:polls", doc: "View a channel’s polls.";
|
||||
(?) ChannelReadPredictions, scope: "channel:read:predictions", doc: "View a channel’s Channel Points Predictions.";
|
||||
+ ChannelReadRedemptions, scope: "channel:read:redemptions", doc: "View Channel Points custom rewards and their redemptions on a channel.";
|
||||
- ChannelReadStreamKey, scope: "channel:read:stream_key", doc: "View an authorized user’s stream key.";
|
||||
+ ChannelReadSubscriptions, scope: "channel:read:subscriptions", doc: "View a list of all subscribers to a channel and check if a user is subscribed to a channel.";
|
||||
- ChannelSubscriptions, scope: "channel_subscriptions", doc: "\\[DEPRECATED\\] Read all subscribers to your channel.";
|
||||
[YES] ChatEdit, scope: "chat:edit", doc: "Send live stream chat and rooms messages.";
|
||||
[YES] ChatRead, scope: "chat:read", doc: "View live stream chat and rooms messages.";
|
||||
(?) ClipsEdit, scope: "clips:edit", doc: "Manage Clips for a channel.";
|
||||
(?) ModerationRead, scope: "moderation:read", doc: "View a channel’s moderation data including Moderators, Bans, Timeouts, and Automod settings.";
|
||||
(?) ModeratorManageAutoMod, scope: "moderator:manage:automod", doc: "Manage messages held for review by AutoMod in channels where you are a moderator.";
|
||||
- UserEdit, scope: "user:edit", doc: "Manage a user object.";
|
||||
- UserEditBroadcast, scope: "user:edit:broadcast", doc: "Edit your channel's broadcast configuration, including extension configuration. (This scope implies user:read:broadcast capability.)";
|
||||
- UserEditFollows, scope: "user:edit:follows", doc: "Edit a user’s follows.";
|
||||
- UserManageBlockedUsers, scope: "user:manage:blocked_users", doc: "Manage the block list of a user.";
|
||||
- UserReadBlockedUsers, scope: "user:read:blocked_users", doc: "View the block list of a user.";
|
||||
- UserReadBroadcast, scope: "user:read:broadcast", doc: "View a user’s broadcasting configuration, including Extension configurations.";
|
||||
- UserReadEmail, scope: "user:read:email", doc: "Read an authorized user’s email address.";
|
||||
- UserReadFollows, scope: "user:read:follows", doc: "View the list of channels a user follows.";
|
||||
(?) UserReadSubscriptions, scope: "user:read:subscriptions", doc: "View if an authorized user is subscribed to specific channels.";
|
||||
- WhispersEdit, scope: "whispers:edit", doc: "Send whisper messages.";
|
||||
- WhispersRead, scope: "whispers:read", doc: "View your whisper messages.";
|
||||
*/
|
||||
|
||||
UserTokenBuilder::new(client_id, client_secret, redirect_url.clone())
|
||||
.set_scopes(vec![
|
||||
Scope::BitsRead, // Using bits to cheer (cost money, larger streams)
|
||||
Scope::ChannelReadRedemptions, // Channel points redeemed (free points, smaller streams)
|
||||
Scope::ChannelReadSubscriptions, // List subscribing (paying) users
|
||||
Scope::ChatEdit, // IRC send
|
||||
Scope::ChatRead, // IRC read
|
||||
])
|
||||
.force_verify(force_verify)
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
use container_common::anyhow_result::AnyhowResult;
|
||||
|
||||
/// Standardized way to read Twitch secrets.
|
||||
/// These are used in several different apps.
|
||||
#[derive(Clone, serde::Deserialize)]
|
||||
pub struct TwitchSecrets {
|
||||
pub app_client_id: String,
|
||||
pub app_client_secret: String,
|
||||
}
|
||||
|
||||
impl TwitchSecrets {
|
||||
pub fn new(
|
||||
app_client_id: &str,
|
||||
app_client_secret: &str,
|
||||
) -> Self {
|
||||
Self {
|
||||
app_client_id: app_client_id.to_string(),
|
||||
app_client_secret: app_client_secret.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_env() -> AnyhowResult<Self> {
|
||||
Ok(Self::new(
|
||||
&easyenv::get_env_string_required("TWITCH_APP_CLIENT_ID")?,
|
||||
&easyenv::get_env_string_required("TWITCH_APP_CLIENT_SECRET")?,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
use container_common::anyhow_result::AnyhowResult;
|
||||
|
||||
/// Twitch says to encode these as strings, but the Twitch Rust libraries
|
||||
/// still deal in integers (uh oh). This centralizes type juggling.
|
||||
#[derive(Clone)]
|
||||
pub struct TwitchUserId {
|
||||
string_user_id: String,
|
||||
numeric_user_id: u32,
|
||||
}
|
||||
|
||||
impl TwitchUserId {
|
||||
|
||||
pub fn from_str(twitch_user_id: &str) -> AnyhowResult<Self> {
|
||||
let numeric_id = twitch_user_id.parse::<u32>()?;
|
||||
Ok(Self {
|
||||
string_user_id: twitch_user_id.to_string(),
|
||||
numeric_user_id: numeric_id,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn from_numeric(twitch_user_id: u32) -> Self {
|
||||
Self {
|
||||
string_user_id: twitch_user_id.to_string(),
|
||||
numeric_user_id: twitch_user_id,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_numeric(&self) -> u32 {
|
||||
self.numeric_user_id
|
||||
}
|
||||
|
||||
pub fn get_str(&self) -> &str {
|
||||
&self.string_user_id
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,7 @@ my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
# External
|
||||
dotenv = "0.15.0"
|
||||
hostname = "0.4.0"
|
||||
hostname = "0.3.1"
|
||||
log = "0.4.14"
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -28,4 +28,3 @@ anyhow = "1.0.86"
|
||||
|
||||
# In-memory caching
|
||||
lru_time_cache = "0.11.11"
|
||||
sieve-cache = "0.2.1"
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
use std::hash::Hash;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use anyhow::{anyhow, bail};
|
||||
use sieve_cache::SieveCache;
|
||||
|
||||
use errors::AnyhowResult;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ArcSieve<K: Eq + Hash + Clone, V: Clone + ?Sized> {
|
||||
cache: Arc<Mutex<SieveCache<K, V>>>,
|
||||
}
|
||||
|
||||
impl <K: Eq + Hash + Clone, V: Clone + ?Sized> ArcSieve<K, V> {
|
||||
|
||||
pub fn with_capacity(capacity: usize) -> AnyhowResult<Self> {
|
||||
let cache = SieveCache::new(capacity)
|
||||
.map_err(|err| anyhow!("could not create cache: {:?}", err))?;
|
||||
Ok(Self {
|
||||
cache: Arc::new(Mutex::new(cache)),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn store(&self, key: K, value: V) -> AnyhowResult<()> {
|
||||
match self.cache.lock() {
|
||||
Err(e) => bail!("could not unlock mutex to write: {:?}", e),
|
||||
Ok(mut cache) => {
|
||||
cache.insert(key, value);
|
||||
},
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn store_copy(&self, key: &K, value: &V) -> AnyhowResult<()> {
|
||||
match self.cache.lock() {
|
||||
Err(e) => bail!("could not unlock mutex to write: {:?}", e),
|
||||
Ok(mut cache) => {
|
||||
cache.insert(key.clone(), value.clone());
|
||||
},
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_copy(&self, key: &K) -> AnyhowResult<Option<V>> {
|
||||
let maybe_copy = match self.cache.lock() {
|
||||
Err(e) => bail!("could not unlock mutex to read: {:?}", e),
|
||||
Ok(mut cache) => {
|
||||
cache.get(key).map(|inner| inner.clone())
|
||||
},
|
||||
};
|
||||
Ok(maybe_copy)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::arc_sieve::ArcSieve;
|
||||
|
||||
#[test]
|
||||
fn test_get_copy() {
|
||||
let sieve : ArcSieve<String, String> = ArcSieve::with_capacity(1).unwrap();
|
||||
let key = "key".to_string();
|
||||
let value = "value".to_string();
|
||||
|
||||
sieve.store_copy(&key, &value).unwrap();
|
||||
let maybe_value = sieve.get_copy(&key).unwrap();
|
||||
assert_eq!(maybe_value, Some("value".to_string()));
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,6 @@
|
||||
#![allow(dead_code)]
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
pub mod arc_sieve;
|
||||
pub mod multi_item_ttl_cache;
|
||||
pub mod single_item_ttl_cache;
|
||||
pub mod ttl_key_counter;
|
||||
|
||||
@@ -24,9 +24,9 @@ errors = { path = "../errors" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
# External
|
||||
hmac = "0.10.1" # jwt signing
|
||||
hmac = "0.10.0" # jwt signing
|
||||
jwt = "0.13.0"
|
||||
sha2 = "0.9.9" # hmac signing
|
||||
sha2 = "0.9.5" # hmac signing
|
||||
|
||||
[dev-dependencies]
|
||||
# None yet
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user