mirror of
https://github.com/storytold/artcraft.git
synced 2026-10-24 02:29:32 -04:00
Compare commits
67
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0033af73ce | ||
|
|
b5fcc3cdfa | ||
|
|
e986a44e9d | ||
|
|
28770ef736 | ||
|
|
894084fba6 | ||
|
|
4bf1a25fbb | ||
|
|
b0a9342194 | ||
|
|
3cc1ea6935 | ||
|
|
b74cf7853d | ||
|
|
3cdce86162 | ||
|
|
b0a87e83a0 | ||
|
|
979c234ed2 | ||
|
|
4837106d37 | ||
|
|
cfd92e814d | ||
|
|
6d27214a14 | ||
|
|
b628fb0a11 | ||
|
|
456b9e1ce6 | ||
|
|
6f7b6da595 | ||
|
|
18ad28135f | ||
|
|
ff4a3115d2 | ||
|
|
ccae943037 | ||
|
|
12ef105ced | ||
|
|
b27070e23e | ||
|
|
8e45a4ea45 | ||
|
|
a669ac7f03 | ||
|
|
b5ed9acdd4 | ||
|
|
ff2aaa9f3d | ||
|
|
f93421eadc | ||
|
|
b82ffcce86 | ||
|
|
e2c5839d01 | ||
|
|
896e8591ba | ||
|
|
19dcfdc629 | ||
|
|
cec7bce450 | ||
|
|
6cc3062da8 | ||
|
|
efdd03bbbd | ||
|
|
c207356ac5 | ||
|
|
3243cc51b7 | ||
|
|
ee4af2976f | ||
|
|
4fb2a38c68 | ||
|
|
a549ceb609 | ||
|
|
003f0cdeea | ||
|
|
9e0772141a | ||
|
|
542b79dd90 | ||
|
|
363f8cbc96 | ||
|
|
f2e75f8637 | ||
|
|
f48cbb7978 | ||
|
|
edd5cd6156 | ||
|
|
37c016cecb | ||
|
|
1a3e111dd6 | ||
|
|
0c456d957c | ||
|
|
85ecce7b38 | ||
|
|
2f1d682438 | ||
|
|
c6fbfaa6ba | ||
|
|
038401bff4 | ||
|
|
e1c7231d96 | ||
|
|
1e11fdb35d | ||
|
|
74c477b045 | ||
|
|
042fa1574d | ||
|
|
4387e6326f | ||
|
|
3ad2b744b7 | ||
|
|
8bf85b637b | ||
|
|
50c3b5ed65 | ||
|
|
df15395bf7 | ||
|
|
5666d58da0 | ||
|
|
0a85e9c581 | ||
|
|
bd0ce25d94 | ||
|
|
951afc2e5d |
+3
-3
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nINSERT INTO generic_inference_jobs\nSET\n token = ?,\n uuid_idempotency_token = ?,\n\n inference_category = ?,\n maybe_model_type = ?,\n maybe_model_token = ?,\n\n maybe_input_source_token = ?,\n maybe_input_source_token_type = ?,\n\n maybe_raw_inference_text = ?,\n\n maybe_inference_args = ?,\n\n maybe_creator_user_token = ?,\n maybe_creator_anonymous_visitor_token = ?,\n creator_ip_address = ?,\n\n creator_set_visibility = ?,\n\n priority_level = ?,\n is_keepalive_required = ?,\n\n is_debug_request = ?,\n maybe_routing_tag = ?,\n\n status = \"pending\"\n ",
|
||||
"query": "\nINSERT INTO generic_inference_jobs\nSET\n token = ?,\n uuid_idempotency_token = ?,\n\n inference_category = ?,\n maybe_model_type = ?,\n maybe_model_token = ?,\n\n maybe_input_source_token = ?,\n maybe_input_source_token_type = ?,\n\n maybe_raw_inference_text = ?,\n\n maybe_inference_args = ?,\n\n maybe_creator_user_token = ?,\n maybe_creator_anonymous_visitor_token = ?,\n creator_ip_address = ?,\n\n creator_set_visibility = ?,\n\n priority_level = ?,\n is_keepalive_required = ?,\n max_duration_seconds = ?,\n\n is_debug_request = ?,\n maybe_routing_tag = ?,\n\n status = \"pending\"\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 17
|
||||
"Right": 18
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "b1750559783bcd55b2ae139372a4782ae363787a840a32f5c17c8408dbf15bc7"
|
||||
"hash": "0d780caac7560f84efb50bd2ed876cbdd728b32e26b73dfbb3009ada12985405"
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\n INSERT INTO model_weights\n SET\n token = ?,\n weights_type = ?,\n weights_category = ?,\n title = ?,\n maybe_thumbnail_token = ?,\n description_markdown = ?,\n description_rendered_html = ?,\n creator_user_token = ?,\n creator_ip_address = ?,\n creator_set_visibility = ?,\n maybe_last_update_user_token = ?,\n original_download_url = ?,\n original_filename = ?,\n file_size_bytes = ?,\n file_checksum_sha2 = ?,\n private_bucket_hash = ?,\n maybe_private_bucket_prefix = ?,\n maybe_private_bucket_extension = ?,\n cached_user_ratings_total_count = ?,\n cached_user_ratings_positive_count = ?,\n cached_user_ratings_negative_count = ?,\n maybe_cached_user_ratings_ratio = ?,\n version = ?\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 23
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "274cfb1e3caca706e3dbc3d95064e0f4b354c936f8de948070854920f265cc41"
|
||||
}
|
||||
+355
@@ -0,0 +1,355 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\n SELECT \n mw.token as `token: tokens::tokens::model_weights::ModelWeightToken`,\n mw.title,\n mw.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n mw.weights_category as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n mw.maybe_thumbnail_token,\n mw.description_markdown,\n mw.description_rendered_html,\n users.token as `creator_user_token: tokens::tokens::users::UserToken`,\n users.username as creator_username,\n users.display_name as creator_display_name,\n users.email_gravatar_hash as creator_email_gravatar_hash,\n mw.creator_ip_address,\n mw.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n mw.maybe_last_update_user_token as `maybe_last_update_user_token: tokens::tokens::users::UserToken`,\n mw.original_download_url,\n mw.original_filename,\n mw.file_size_bytes,\n mw.file_checksum_sha2,\n mw.private_bucket_hash,\n mw.maybe_private_bucket_prefix,\n mw.maybe_private_bucket_extension,\n mw.cached_user_ratings_negative_count,\n mw.cached_user_ratings_positive_count,\n mw.cached_user_ratings_total_count,\n mw.maybe_cached_user_ratings_ratio,\n mw.cached_user_ratings_last_updated_at,\n mw.version,\n mw.created_at,\n mw.updated_at,\n mw.user_deleted_at,\n mw.mod_deleted_at\n FROM model_weights as mw\n JOIN users\n ON users.token = mw.creator_user_token\n WHERE\n users.username = ?\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "token: tokens::tokens::model_weights::ModelWeightToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "title",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 1020
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "weights_type: enums::by_table::model_weights::weights_types::WeightsType",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "weights_category: enums::by_table::model_weights::weights_category::WeightsCategory",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "maybe_thumbnail_token",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "description_markdown",
|
||||
"type_info": {
|
||||
"type": "Blob",
|
||||
"flags": "NOT_NULL | BLOB | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 262140
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"name": "description_rendered_html",
|
||||
"type_info": {
|
||||
"type": "Blob",
|
||||
"flags": "NOT_NULL | BLOB | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 262140
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"name": "creator_user_token: tokens::tokens::users::UserToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"name": "creator_username",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 9,
|
||||
"name": "creator_display_name",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 10,
|
||||
"name": "creator_email_gravatar_hash",
|
||||
"type_info": {
|
||||
"type": "String",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 11,
|
||||
"name": "creator_ip_address",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 160
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 12,
|
||||
"name": "creator_set_visibility: enums::common::visibility::Visibility",
|
||||
"type_info": {
|
||||
"type": "String",
|
||||
"flags": "NOT_NULL | BINARY | ENUM",
|
||||
"char_set": 224,
|
||||
"max_size": 28
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 13,
|
||||
"name": "maybe_last_update_user_token: tokens::tokens::users::UserToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 14,
|
||||
"name": "original_download_url",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 2048
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 15,
|
||||
"name": "original_filename",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 1020
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 16,
|
||||
"name": "file_size_bytes",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
"flags": "NOT_NULL",
|
||||
"char_set": 63,
|
||||
"max_size": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 17,
|
||||
"name": "file_checksum_sha2",
|
||||
"type_info": {
|
||||
"type": "String",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 256
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 18,
|
||||
"name": "private_bucket_hash",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 19,
|
||||
"name": "maybe_private_bucket_prefix",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 64
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 20,
|
||||
"name": "maybe_private_bucket_extension",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 64
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 21,
|
||||
"name": "cached_user_ratings_negative_count",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
"flags": "NOT_NULL | UNSIGNED",
|
||||
"char_set": 63,
|
||||
"max_size": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 22,
|
||||
"name": "cached_user_ratings_positive_count",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
"flags": "NOT_NULL | UNSIGNED",
|
||||
"char_set": 63,
|
||||
"max_size": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 23,
|
||||
"name": "cached_user_ratings_total_count",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
"flags": "NOT_NULL | UNSIGNED",
|
||||
"char_set": 63,
|
||||
"max_size": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 24,
|
||||
"name": "maybe_cached_user_ratings_ratio",
|
||||
"type_info": {
|
||||
"type": "Float",
|
||||
"flags": "",
|
||||
"char_set": 63,
|
||||
"max_size": 12
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 25,
|
||||
"name": "cached_user_ratings_last_updated_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
"flags": "NOT_NULL | BINARY | TIMESTAMP",
|
||||
"char_set": 63,
|
||||
"max_size": 19
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 26,
|
||||
"name": "version",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
"flags": "NOT_NULL",
|
||||
"char_set": 63,
|
||||
"max_size": 11
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 27,
|
||||
"name": "created_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
"flags": "NOT_NULL | BINARY | TIMESTAMP",
|
||||
"char_set": 63,
|
||||
"max_size": 19
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 28,
|
||||
"name": "updated_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
"flags": "NOT_NULL | BINARY | TIMESTAMP | ON_UPDATE_NOW",
|
||||
"char_set": 63,
|
||||
"max_size": 19
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 29,
|
||||
"name": "user_deleted_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
"flags": "BINARY",
|
||||
"char_set": 63,
|
||||
"max_size": 19
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 30,
|
||||
"name": "mod_deleted_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
"flags": "BINARY",
|
||||
"char_set": 63,
|
||||
"max_size": 19
|
||||
}
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "3d586592422727dcc928574966bdf5081ac69fdbb856fffcbd68187fd99c4642"
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nUPDATE model_weights\nSET\n mod_deleted_at = NULL\nWHERE\n token = ?\nLIMIT 1\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "3dfc7f22c16543116c4ca17f5bee0336f5cfa1522681ba1bb6b1874cd8f13297"
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\n UPDATE model_weights\n SET\n title = ?,\n description_markdown = ?,\n maybe_thumbnail_token = ?,\n description_rendered_html = ?,\n creator_set_visibility = ?,\n version = version + 1\n WHERE token = ?\n LIMIT 1\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 6
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "4ed42766cc0ca2234b7bc1837d645d05198d483564b39a2a8b8034df25e287a4"
|
||||
}
|
||||
+322
@@ -0,0 +1,322 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\n SELECT\n wt.token as `token: tokens::tokens::model_weights::ModelWeightToken`,\n wt.title,\n wt.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n wt.weights_category as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n wt.maybe_thumbnail_token,\n wt.description_markdown,\n wt.description_rendered_html,\n wt.creator_user_token as `creator_user_token: tokens::tokens::users::UserToken`,\n wt.creator_ip_address,\n wt.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n wt.maybe_last_update_user_token as `maybe_last_update_user_token: tokens::tokens::users::UserToken`,\n wt.original_download_url,\n wt.original_filename,\n wt.file_size_bytes,\n wt.file_checksum_sha2,\n wt.private_bucket_hash,\n wt.maybe_private_bucket_prefix,\n wt.maybe_private_bucket_extension,\n wt.cached_user_ratings_negative_count,\n wt.cached_user_ratings_positive_count,\n wt.cached_user_ratings_total_count,\n wt.maybe_cached_user_ratings_ratio,\n wt.cached_user_ratings_last_updated_at,\n wt.version,\n wt.created_at,\n wt.updated_at,\n wt.user_deleted_at,\n wt.mod_deleted_at\n FROM model_weights as wt\n WHERE\n wt.token = ?\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "token: tokens::tokens::model_weights::ModelWeightToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "title",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 1020
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "weights_type: enums::by_table::model_weights::weights_types::WeightsType",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "weights_category: enums::by_table::model_weights::weights_category::WeightsCategory",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "maybe_thumbnail_token",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "description_markdown",
|
||||
"type_info": {
|
||||
"type": "Blob",
|
||||
"flags": "NOT_NULL | BLOB | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 262140
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"name": "description_rendered_html",
|
||||
"type_info": {
|
||||
"type": "Blob",
|
||||
"flags": "NOT_NULL | BLOB | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 262140
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"name": "creator_user_token: tokens::tokens::users::UserToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"name": "creator_ip_address",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 160
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 9,
|
||||
"name": "creator_set_visibility: enums::common::visibility::Visibility",
|
||||
"type_info": {
|
||||
"type": "String",
|
||||
"flags": "NOT_NULL | BINARY | ENUM",
|
||||
"char_set": 224,
|
||||
"max_size": 28
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 10,
|
||||
"name": "maybe_last_update_user_token: tokens::tokens::users::UserToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 11,
|
||||
"name": "original_download_url",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 2048
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 12,
|
||||
"name": "original_filename",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 1020
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 13,
|
||||
"name": "file_size_bytes",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
"flags": "NOT_NULL",
|
||||
"char_set": 63,
|
||||
"max_size": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 14,
|
||||
"name": "file_checksum_sha2",
|
||||
"type_info": {
|
||||
"type": "String",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 256
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 15,
|
||||
"name": "private_bucket_hash",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 16,
|
||||
"name": "maybe_private_bucket_prefix",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 64
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 17,
|
||||
"name": "maybe_private_bucket_extension",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 64
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 18,
|
||||
"name": "cached_user_ratings_negative_count",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
"flags": "NOT_NULL | UNSIGNED",
|
||||
"char_set": 63,
|
||||
"max_size": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 19,
|
||||
"name": "cached_user_ratings_positive_count",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
"flags": "NOT_NULL | UNSIGNED",
|
||||
"char_set": 63,
|
||||
"max_size": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 20,
|
||||
"name": "cached_user_ratings_total_count",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
"flags": "NOT_NULL | UNSIGNED",
|
||||
"char_set": 63,
|
||||
"max_size": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 21,
|
||||
"name": "maybe_cached_user_ratings_ratio",
|
||||
"type_info": {
|
||||
"type": "Float",
|
||||
"flags": "",
|
||||
"char_set": 63,
|
||||
"max_size": 12
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 22,
|
||||
"name": "cached_user_ratings_last_updated_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
"flags": "NOT_NULL | BINARY | TIMESTAMP",
|
||||
"char_set": 63,
|
||||
"max_size": 19
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 23,
|
||||
"name": "version",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
"flags": "NOT_NULL",
|
||||
"char_set": 63,
|
||||
"max_size": 11
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 24,
|
||||
"name": "created_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
"flags": "NOT_NULL | BINARY | TIMESTAMP",
|
||||
"char_set": 63,
|
||||
"max_size": 19
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 25,
|
||||
"name": "updated_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
"flags": "NOT_NULL | BINARY | TIMESTAMP | ON_UPDATE_NOW",
|
||||
"char_set": 63,
|
||||
"max_size": 19
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 26,
|
||||
"name": "user_deleted_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
"flags": "BINARY",
|
||||
"char_set": 63,
|
||||
"max_size": 19
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 27,
|
||||
"name": "mod_deleted_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
"flags": "BINARY",
|
||||
"char_set": 63,
|
||||
"max_size": 19
|
||||
}
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "6a94791c8a8f66ee54bb367a4e8c71106bbcbbb205f54c14e3657279e83dabb6"
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nUPDATE model_weights\nSET\n user_deleted_at = CURRENT_TIMESTAMP\nWHERE\n token = ?\nLIMIT 1\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "7487c997706788c670a76da81ce90532b9748c8afcc707436d1f04ed976ce30e"
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nUPDATE model_weights\nSET\n user_deleted_at = NULL\nWHERE\n token = ?\nLIMIT 1\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "7dbfbb21d502aad7859016fd287c57010296011928cf21b036a8dc57f1ef619d"
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\nUPDATE model_weights\nSET\n mod_deleted_at = CURRENT_TIMESTAMP\nWHERE\n token = ?\nLIMIT 1\n ",
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": []
|
||||
},
|
||||
"hash": "9d2c8d49cf9840a547230e5c6febc041f39cd069bcb7a4a94ffb4f1cb3be6d7c"
|
||||
}
|
||||
+355
@@ -0,0 +1,355 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\n SELECT\n mw.token as `token: tokens::tokens::model_weights::ModelWeightToken`,\n mw.title,\n mw.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n mw.weights_category as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n mw.maybe_thumbnail_token,\n mw.description_markdown,\n mw.description_rendered_html,\n users.token as `creator_user_token: tokens::tokens::users::UserToken`,\n users.username as creator_username,\n users.display_name as creator_display_name,\n users.email_gravatar_hash as creator_email_gravatar_hash,\n mw.creator_ip_address,\n mw.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n mw.maybe_last_update_user_token as `maybe_last_update_user_token: tokens::tokens::users::UserToken`,\n mw.original_download_url,\n mw.original_filename,\n mw.file_size_bytes,\n mw.file_checksum_sha2,\n mw.private_bucket_hash,\n mw.maybe_private_bucket_prefix,\n mw.maybe_private_bucket_extension,\n mw.cached_user_ratings_negative_count,\n mw.cached_user_ratings_positive_count,\n mw.cached_user_ratings_total_count,\n mw.maybe_cached_user_ratings_ratio,\n mw.cached_user_ratings_last_updated_at,\n mw.version,\n mw.created_at,\n mw.updated_at,\n mw.user_deleted_at,\n mw.mod_deleted_at\n FROM model_weights as mw\n JOIN users\n ON users.token = mw.creator_user_token\n WHERE\n users.username = ?\n AND mw.user_deleted_at IS NULL\n AND mw.mod_deleted_at IS NULL\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "token: tokens::tokens::model_weights::ModelWeightToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "title",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 1020
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "weights_type: enums::by_table::model_weights::weights_types::WeightsType",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "weights_category: enums::by_table::model_weights::weights_category::WeightsCategory",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "maybe_thumbnail_token",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "description_markdown",
|
||||
"type_info": {
|
||||
"type": "Blob",
|
||||
"flags": "NOT_NULL | BLOB | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 262140
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"name": "description_rendered_html",
|
||||
"type_info": {
|
||||
"type": "Blob",
|
||||
"flags": "NOT_NULL | BLOB | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 262140
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"name": "creator_user_token: tokens::tokens::users::UserToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"name": "creator_username",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 9,
|
||||
"name": "creator_display_name",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 80
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 10,
|
||||
"name": "creator_email_gravatar_hash",
|
||||
"type_info": {
|
||||
"type": "String",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 11,
|
||||
"name": "creator_ip_address",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 160
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 12,
|
||||
"name": "creator_set_visibility: enums::common::visibility::Visibility",
|
||||
"type_info": {
|
||||
"type": "String",
|
||||
"flags": "NOT_NULL | BINARY | ENUM",
|
||||
"char_set": 224,
|
||||
"max_size": 28
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 13,
|
||||
"name": "maybe_last_update_user_token: tokens::tokens::users::UserToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 14,
|
||||
"name": "original_download_url",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 2048
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 15,
|
||||
"name": "original_filename",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 1020
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 16,
|
||||
"name": "file_size_bytes",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
"flags": "NOT_NULL",
|
||||
"char_set": 63,
|
||||
"max_size": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 17,
|
||||
"name": "file_checksum_sha2",
|
||||
"type_info": {
|
||||
"type": "String",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 256
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 18,
|
||||
"name": "private_bucket_hash",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 19,
|
||||
"name": "maybe_private_bucket_prefix",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 64
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 20,
|
||||
"name": "maybe_private_bucket_extension",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 64
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 21,
|
||||
"name": "cached_user_ratings_negative_count",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
"flags": "NOT_NULL | UNSIGNED",
|
||||
"char_set": 63,
|
||||
"max_size": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 22,
|
||||
"name": "cached_user_ratings_positive_count",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
"flags": "NOT_NULL | UNSIGNED",
|
||||
"char_set": 63,
|
||||
"max_size": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 23,
|
||||
"name": "cached_user_ratings_total_count",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
"flags": "NOT_NULL | UNSIGNED",
|
||||
"char_set": 63,
|
||||
"max_size": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 24,
|
||||
"name": "maybe_cached_user_ratings_ratio",
|
||||
"type_info": {
|
||||
"type": "Float",
|
||||
"flags": "",
|
||||
"char_set": 63,
|
||||
"max_size": 12
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 25,
|
||||
"name": "cached_user_ratings_last_updated_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
"flags": "NOT_NULL | BINARY | TIMESTAMP",
|
||||
"char_set": 63,
|
||||
"max_size": 19
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 26,
|
||||
"name": "version",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
"flags": "NOT_NULL",
|
||||
"char_set": 63,
|
||||
"max_size": 11
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 27,
|
||||
"name": "created_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
"flags": "NOT_NULL | BINARY | TIMESTAMP",
|
||||
"char_set": 63,
|
||||
"max_size": 19
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 28,
|
||||
"name": "updated_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
"flags": "NOT_NULL | BINARY | TIMESTAMP | ON_UPDATE_NOW",
|
||||
"char_set": 63,
|
||||
"max_size": 19
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 29,
|
||||
"name": "user_deleted_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
"flags": "BINARY",
|
||||
"char_set": 63,
|
||||
"max_size": 19
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 30,
|
||||
"name": "mod_deleted_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
"flags": "BINARY",
|
||||
"char_set": 63,
|
||||
"max_size": 19
|
||||
}
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "a6ed8524fb5339fed17bec6611f8f56b6bdee35bac63c9eacbe21eb032a6a831"
|
||||
}
|
||||
+322
@@ -0,0 +1,322 @@
|
||||
{
|
||||
"db_name": "MySQL",
|
||||
"query": "\n SELECT\n wt.token as `token: tokens::tokens::model_weights::ModelWeightToken`,\n wt.title,\n wt.weights_type as `weights_type: enums::by_table::model_weights::weights_types::WeightsType`,\n wt.weights_category as `weights_category: enums::by_table::model_weights::weights_category::WeightsCategory`,\n wt.maybe_thumbnail_token,\n wt.description_markdown,\n wt.description_rendered_html,\n wt.creator_user_token as `creator_user_token: tokens::tokens::users::UserToken`,\n wt.creator_ip_address,\n wt.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,\n wt.maybe_last_update_user_token as `maybe_last_update_user_token: tokens::tokens::users::UserToken`,\n wt.original_download_url,\n wt.original_filename,\n wt.file_size_bytes,\n wt.file_checksum_sha2,\n wt.private_bucket_hash,\n wt.maybe_private_bucket_prefix,\n wt.maybe_private_bucket_extension,\n wt.cached_user_ratings_negative_count,\n wt.cached_user_ratings_positive_count,\n wt.cached_user_ratings_total_count,\n wt.maybe_cached_user_ratings_ratio,\n wt.cached_user_ratings_last_updated_at,\n wt.version,\n wt.created_at,\n wt.updated_at,\n wt.user_deleted_at,\n wt.mod_deleted_at\n FROM model_weights as wt\n WHERE\n wt.token = ?\n AND wt.user_deleted_at IS NULL\n AND wt.mod_deleted_at IS NULL\n ",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"ordinal": 0,
|
||||
"name": "token: tokens::tokens::model_weights::ModelWeightToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | UNIQUE_KEY | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 1,
|
||||
"name": "title",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 1020
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 2,
|
||||
"name": "weights_type: enums::by_table::model_weights::weights_types::WeightsType",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 3,
|
||||
"name": "weights_category: enums::by_table::model_weights::weights_category::WeightsCategory",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 4,
|
||||
"name": "maybe_thumbnail_token",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 5,
|
||||
"name": "description_markdown",
|
||||
"type_info": {
|
||||
"type": "Blob",
|
||||
"flags": "NOT_NULL | BLOB | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 262140
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 6,
|
||||
"name": "description_rendered_html",
|
||||
"type_info": {
|
||||
"type": "Blob",
|
||||
"flags": "NOT_NULL | BLOB | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 262140
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 7,
|
||||
"name": "creator_user_token: tokens::tokens::users::UserToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 8,
|
||||
"name": "creator_ip_address",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 160
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 9,
|
||||
"name": "creator_set_visibility: enums::common::visibility::Visibility",
|
||||
"type_info": {
|
||||
"type": "String",
|
||||
"flags": "NOT_NULL | BINARY | ENUM",
|
||||
"char_set": 224,
|
||||
"max_size": 28
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 10,
|
||||
"name": "maybe_last_update_user_token: tokens::tokens::users::UserToken",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 11,
|
||||
"name": "original_download_url",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 2048
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 12,
|
||||
"name": "original_filename",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 1020
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 13,
|
||||
"name": "file_size_bytes",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
"flags": "NOT_NULL",
|
||||
"char_set": 63,
|
||||
"max_size": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 14,
|
||||
"name": "file_checksum_sha2",
|
||||
"type_info": {
|
||||
"type": "String",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 256
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 15,
|
||||
"name": "private_bucket_hash",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "NOT_NULL | BINARY | NO_DEFAULT_VALUE",
|
||||
"char_set": 224,
|
||||
"max_size": 128
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 16,
|
||||
"name": "maybe_private_bucket_prefix",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 64
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 17,
|
||||
"name": "maybe_private_bucket_extension",
|
||||
"type_info": {
|
||||
"type": "VarString",
|
||||
"flags": "BINARY",
|
||||
"char_set": 224,
|
||||
"max_size": 64
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 18,
|
||||
"name": "cached_user_ratings_negative_count",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
"flags": "NOT_NULL | UNSIGNED",
|
||||
"char_set": 63,
|
||||
"max_size": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 19,
|
||||
"name": "cached_user_ratings_positive_count",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
"flags": "NOT_NULL | UNSIGNED",
|
||||
"char_set": 63,
|
||||
"max_size": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 20,
|
||||
"name": "cached_user_ratings_total_count",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
"flags": "NOT_NULL | UNSIGNED",
|
||||
"char_set": 63,
|
||||
"max_size": 10
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 21,
|
||||
"name": "maybe_cached_user_ratings_ratio",
|
||||
"type_info": {
|
||||
"type": "Float",
|
||||
"flags": "",
|
||||
"char_set": 63,
|
||||
"max_size": 12
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 22,
|
||||
"name": "cached_user_ratings_last_updated_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
"flags": "NOT_NULL | BINARY | TIMESTAMP",
|
||||
"char_set": 63,
|
||||
"max_size": 19
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 23,
|
||||
"name": "version",
|
||||
"type_info": {
|
||||
"type": "Long",
|
||||
"flags": "NOT_NULL",
|
||||
"char_set": 63,
|
||||
"max_size": 11
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 24,
|
||||
"name": "created_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
"flags": "NOT_NULL | BINARY | TIMESTAMP",
|
||||
"char_set": 63,
|
||||
"max_size": 19
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 25,
|
||||
"name": "updated_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
"flags": "NOT_NULL | BINARY | TIMESTAMP | ON_UPDATE_NOW",
|
||||
"char_set": 63,
|
||||
"max_size": 19
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 26,
|
||||
"name": "user_deleted_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
"flags": "BINARY",
|
||||
"char_set": 63,
|
||||
"max_size": 19
|
||||
}
|
||||
},
|
||||
{
|
||||
"ordinal": 27,
|
||||
"name": "mod_deleted_at",
|
||||
"type_info": {
|
||||
"type": "Timestamp",
|
||||
"flags": "BINARY",
|
||||
"char_set": 63,
|
||||
"max_size": 19
|
||||
}
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
},
|
||||
"nullable": [
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "f0b5767d52c389660d1859e628c746f6f33a9e1c25f21f66aeeb0784df768c8e"
|
||||
}
|
||||
Generated
+141
-159
@@ -736,12 +736,6 @@ dependencies = [
|
||||
"rustc-demangle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base-x"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.11.0"
|
||||
@@ -1175,6 +1169,15 @@ dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "collections"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"errors",
|
||||
"my-workspace-hack",
|
||||
"rand 0.8.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "color_quant"
|
||||
version = "1.1.0"
|
||||
@@ -1253,12 +1256,6 @@ version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f"
|
||||
|
||||
[[package]]
|
||||
name = "const_fn"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fbdcdcb6d86f71c5e97409ad45898af11cbc995b4ee8112d59095a28d376c935"
|
||||
|
||||
[[package]]
|
||||
name = "constant_time_eq"
|
||||
version = "0.1.5"
|
||||
@@ -1867,12 +1864,6 @@ dependencies = [
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "discard"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
|
||||
|
||||
[[package]]
|
||||
name = "displaydoc"
|
||||
version = "0.2.4"
|
||||
@@ -2003,7 +1994,7 @@ name = "easyenv"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"dotenv",
|
||||
"env_logger 0.10.1",
|
||||
"env_logger",
|
||||
"log",
|
||||
"my-workspace-hack",
|
||||
"storyteller_root",
|
||||
@@ -2184,26 +2175,13 @@ dependencies = [
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
|
||||
dependencies = [
|
||||
"atty",
|
||||
"humantime 1.3.0",
|
||||
"log",
|
||||
"regex",
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95b3f3e67048839cb0d0781f445682a35113da7121f7c949db0e2be96a4fbece"
|
||||
dependencies = [
|
||||
"humantime 2.1.0",
|
||||
"humantime",
|
||||
"is-terminal",
|
||||
"log",
|
||||
"regex",
|
||||
@@ -2296,6 +2274,7 @@ name = "filesys"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"errors",
|
||||
"log",
|
||||
"my-workspace-hack",
|
||||
]
|
||||
|
||||
@@ -2848,15 +2827,6 @@ version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
|
||||
dependencies = [
|
||||
"quick-error",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "2.1.0"
|
||||
@@ -2994,6 +2964,7 @@ checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.14.2",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3032,9 +3003,9 @@ dependencies = [
|
||||
"buckets",
|
||||
"chrono",
|
||||
"cloud_storage",
|
||||
"collections",
|
||||
"concurrency",
|
||||
"config",
|
||||
"container_common",
|
||||
"dotenv",
|
||||
"easyenv",
|
||||
"enums",
|
||||
@@ -3045,6 +3016,7 @@ dependencies = [
|
||||
"hyper",
|
||||
"images",
|
||||
"jobs_common",
|
||||
"lfu",
|
||||
"log",
|
||||
"media",
|
||||
"memory_caching",
|
||||
@@ -3399,7 +3371,7 @@ name = "logging"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"dotenv",
|
||||
"env_logger 0.10.1",
|
||||
"env_logger",
|
||||
"log",
|
||||
"my-workspace-hack",
|
||||
]
|
||||
@@ -3755,7 +3727,7 @@ dependencies = [
|
||||
"syn 1.0.109",
|
||||
"syn 2.0.39",
|
||||
"time 0.3.30",
|
||||
"time-macros 0.2.15",
|
||||
"time-macros",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"tracing",
|
||||
@@ -3792,7 +3764,7 @@ dependencies = [
|
||||
"serial_test",
|
||||
"sqlx",
|
||||
"tokens",
|
||||
"tokio 1.34.0",
|
||||
"tokio",
|
||||
"toml",
|
||||
]
|
||||
|
||||
@@ -3852,14 +3824,14 @@ name = "newrelic-telemetry"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"env_logger 0.7.1",
|
||||
"env_logger",
|
||||
"flate2",
|
||||
"futures 0.3.29",
|
||||
"hyper",
|
||||
"hyper-tls",
|
||||
"log",
|
||||
"my-workspace-hack",
|
||||
"rand 0.7.3",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
@@ -4423,10 +4395,28 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-hack"
|
||||
version = "0.5.20+deprecated"
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068"
|
||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||
dependencies = [
|
||||
"proc-macro-error-attr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error-attr"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
@@ -4467,12 +4457,6 @@ dependencies = [
|
||||
"bytemuck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quick-error"
|
||||
version = "1.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
|
||||
|
||||
[[package]]
|
||||
name = "quick-xml"
|
||||
version = "0.26.0"
|
||||
@@ -4736,7 +4720,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"time 0.2.27",
|
||||
"time 0.3.30",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4917,6 +4901,41 @@ dependencies = [
|
||||
"quick-xml 0.30.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-embed"
|
||||
version = "8.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1e7d90385b59f0a6bf3d3b757f3ca4ece2048265d70db20a2016043d4509a40"
|
||||
dependencies = [
|
||||
"rust-embed-impl",
|
||||
"rust-embed-utils",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-embed-impl"
|
||||
version = "8.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c3d8c6fd84090ae348e63a84336b112b5c3918b3bf0493a581f7bd8ee623c29"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rust-embed-utils",
|
||||
"shellexpand",
|
||||
"syn 2.0.39",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-embed-utils"
|
||||
version = "8.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "873feff8cb7bf86fdf0a71bb21c95159f4e4a37dd7a4bd1855a940909b583ada"
|
||||
dependencies = [
|
||||
"sha2 0.10.8",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-ini"
|
||||
version = "0.18.0"
|
||||
@@ -5452,6 +5471,15 @@ dependencies = [
|
||||
"digest 0.10.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shellexpand"
|
||||
version = "2.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7ccc8076840c4da029af4f87e4e8daeb0fca6b87bbb02e10cb60b791450e11e4"
|
||||
dependencies = [
|
||||
"dirs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.1"
|
||||
@@ -5836,70 +5864,12 @@ dependencies = [
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "standback"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff"
|
||||
dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "stdweb"
|
||||
version = "0.4.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5"
|
||||
dependencies = [
|
||||
"discard",
|
||||
"rustc_version 0.2.3",
|
||||
"stdweb-derive",
|
||||
"stdweb-internal-macros",
|
||||
"stdweb-internal-runtime",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stdweb-derive"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stdweb-internal-macros"
|
||||
version = "0.2.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11"
|
||||
dependencies = [
|
||||
"base-x",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"sha1 0.6.1",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stdweb-internal-runtime"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0"
|
||||
|
||||
[[package]]
|
||||
name = "storyteller-web"
|
||||
version = "0.0.1"
|
||||
@@ -5983,7 +5953,7 @@ dependencies = [
|
||||
"speculoos",
|
||||
"sqlx",
|
||||
"symphonia",
|
||||
"time 0.2.27",
|
||||
"time 0.3.30",
|
||||
"tokens",
|
||||
"tokio",
|
||||
"toml",
|
||||
@@ -5993,6 +5963,8 @@ dependencies = [
|
||||
"url_config",
|
||||
"user_input_common",
|
||||
"users_component",
|
||||
"utoipa",
|
||||
"utoipa-swagger-ui",
|
||||
"uuid 0.8.2",
|
||||
]
|
||||
|
||||
@@ -6429,21 +6401,6 @@ dependencies = [
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.2.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242"
|
||||
dependencies = [
|
||||
"const_fn",
|
||||
"libc",
|
||||
"standback",
|
||||
"stdweb",
|
||||
"time-macros 0.1.1",
|
||||
"version_check",
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.30"
|
||||
@@ -6455,7 +6412,7 @@ dependencies = [
|
||||
"powerfmt",
|
||||
"serde",
|
||||
"time-core",
|
||||
"time-macros 0.2.15",
|
||||
"time-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6464,16 +6421,6 @@ version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
|
||||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1"
|
||||
dependencies = [
|
||||
"proc-macro-hack",
|
||||
"time-macros-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.2.15"
|
||||
@@ -6483,19 +6430,6 @@ dependencies = [
|
||||
"time-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time-macros-impl"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f"
|
||||
dependencies = [
|
||||
"proc-macro-hack",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"standback",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.6.0"
|
||||
@@ -6524,6 +6458,7 @@ dependencies = [
|
||||
"sqlx-core",
|
||||
"strum",
|
||||
"toml",
|
||||
"utoipa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6777,6 +6712,7 @@ dependencies = [
|
||||
"dotenv",
|
||||
"easyenv",
|
||||
"enums",
|
||||
"filesys",
|
||||
"google_drive_common",
|
||||
"hashing",
|
||||
"hostname",
|
||||
@@ -6803,10 +6739,12 @@ dependencies = [
|
||||
"chrono",
|
||||
"clap 2.34.0",
|
||||
"cloud_storage",
|
||||
"collections",
|
||||
"config",
|
||||
"container_common",
|
||||
"dotenv",
|
||||
"easyenv",
|
||||
"filesys",
|
||||
"hashing",
|
||||
"hostname",
|
||||
"hyper",
|
||||
@@ -6874,6 +6812,7 @@ dependencies = [
|
||||
"anyhow",
|
||||
"base64 0.21.5",
|
||||
"chrono",
|
||||
"collections",
|
||||
"config",
|
||||
"container_common",
|
||||
"diesel",
|
||||
@@ -6902,7 +6841,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"sha2 0.9.9",
|
||||
"sqlx",
|
||||
"time 0.2.27",
|
||||
"time 0.3.30",
|
||||
"tokens",
|
||||
"tokio",
|
||||
"tokio-tungstenite",
|
||||
@@ -7140,7 +7079,7 @@ dependencies = [
|
||||
"sha2 0.9.9",
|
||||
"sqlx",
|
||||
"strum_macros",
|
||||
"time 0.2.27",
|
||||
"time 0.3.30",
|
||||
"tokens",
|
||||
"toml",
|
||||
"user_input_common",
|
||||
@@ -7158,6 +7097,47 @@ version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
||||
|
||||
[[package]]
|
||||
name = "utoipa"
|
||||
version = "4.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ff05e3bac2c9428f57ade702667753ca3f5cf085e2011fe697de5bfd49aa72d"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"utoipa-gen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utoipa-gen"
|
||||
version = "4.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f0b6f4667edd64be0e820d6631a60433a269710b6ee89ac39525b872b76d61d"
|
||||
dependencies = [
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"syn 2.0.39",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "utoipa-swagger-ui"
|
||||
version = "5.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f839caa8e09dddc3ff1c3112a91ef7da0601075ba5025d9f33ae99c4cb9b6e51"
|
||||
dependencies = [
|
||||
"actix-web",
|
||||
"mime_guess",
|
||||
"regex",
|
||||
"rust-embed",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"utoipa",
|
||||
"zip",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "0.8.2"
|
||||
@@ -7209,6 +7189,7 @@ dependencies = [
|
||||
"container_common",
|
||||
"dotenv",
|
||||
"easyenv",
|
||||
"filesys",
|
||||
"google_drive_common",
|
||||
"hashing",
|
||||
"hostname",
|
||||
@@ -7238,6 +7219,7 @@ dependencies = [
|
||||
"container_common",
|
||||
"dotenv",
|
||||
"easyenv",
|
||||
"filesys",
|
||||
"google_drive_common",
|
||||
"hostname",
|
||||
"hyper",
|
||||
@@ -7480,7 +7462,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"sha2 0.9.9",
|
||||
"sqlx",
|
||||
"time 0.2.27",
|
||||
"time 0.3.30",
|
||||
"tokio",
|
||||
"toml",
|
||||
"twitch_api2",
|
||||
|
||||
@@ -27,6 +27,7 @@ members = [
|
||||
"crates/lib/bootstrap",
|
||||
"crates/lib/caching/memory_caching",
|
||||
"crates/lib/caching/redis_caching",
|
||||
"crates/lib/collections",
|
||||
"crates/lib/concurrency",
|
||||
"crates/lib/cookies",
|
||||
"crates/lib/crockford",
|
||||
|
||||
@@ -29,7 +29,9 @@ Web API Overview
|
||||
* `tts-inference-job` - (*deprecated*) Async TTS inference of Tacotron2 models only
|
||||
* `w2l-download-job` - (*deprecated*) Async download of videos and images
|
||||
* `w2l-inference-job` - (*deprecated*) Async W2L inference
|
||||
|
||||
* Documentation Server:
|
||||
* `docs` - this will run a local swagger server with the endpoints that you have access to, http://127.0.0.1:8989/api-docs/openapi.json use this to port everything over to the post man.
|
||||
|
||||
### PowerStream
|
||||
|
||||
* [PowerStream](https://power.stream) (deprecated) is powered by the following applications:
|
||||
|
||||
@@ -380,3 +380,16 @@ of this error message. You can essentially ignore it.
|
||||
### [Fix] Can't connect to local MySQL after install on Ubuntu
|
||||
|
||||
- If MySql in local dev can't be connected to, [reset the accounts](https://linuxconfig.org/how-to-reset-root-mysql-mariadb-password-on-ubuntu-20-04-focal-fossa-linux).
|
||||
|
||||
### API Server
|
||||
```
|
||||
cargo run --bin docs
|
||||
```
|
||||
This setups an api server with swagger docs to show you responses and requests with each associated endpoint
|
||||
It is run at http://127.0.0.1:8989/
|
||||
To obtain the json for the postman collection go to this url http://127.0.0.1:8989/api-docs/openapi.json
|
||||
We use this: `https://github.com/juhaku/utoipa`
|
||||
The documentation example is in:
|
||||
`crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/inference/enqueue_tts_request.rs`
|
||||
Write into the api doc to:
|
||||
`crates/service/web/storyteller_web/src/api_doc.rs`
|
||||
@@ -8,11 +8,25 @@ update generic_inference_jobs set status = 'dead' where maybe_routing_tag IS NOT
|
||||
-- Get pending jobs
|
||||
select count(*) from generic_inference_jobs where status = 'pending';
|
||||
|
||||
-- Kill outstanding jobs
|
||||
update generic_inference_jobs
|
||||
set status = 'dead'
|
||||
where status IN ('pending', 'started', 'attempt_failed');
|
||||
|
||||
-- Kill outstanding jobs of type
|
||||
update generic_inference_jobs
|
||||
set status = 'dead'
|
||||
where status IN ('pending', 'started', 'attempt_failed')
|
||||
and maybe_model_type IN ('sad_talker', 'so_vits_svc');
|
||||
|
||||
-- Tacotron 2 TTS
|
||||
update generic_inference_jobs
|
||||
set status = 'dead'
|
||||
where status IN ('pending', 'started', 'attempt_failed')
|
||||
and maybe_model_type IN ('tacotron2');
|
||||
|
||||
-- Sad Talker Face Animation
|
||||
update generic_inference_jobs
|
||||
set status = 'dead'
|
||||
where status IN ('pending', 'started', 'attempt_failed')
|
||||
and maybe_model_type IN ('sad_talker');
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ set -euxo pipefail
|
||||
|
||||
# NB: Database used by desktop app for AiChatBot sidecar.
|
||||
# Make sure it has been migrated (use aichatbot-sidecar app directory as root).
|
||||
SQLITE_DATABASE_PATH=./runtime_data/database.db
|
||||
# SQLITE_DATABASE_PATH=./runtime_data/database.db
|
||||
|
||||
# NB: OpenSSL is broken on Ubuntu 22.04 (this is documented elsewhere)
|
||||
# See https://askubuntu.com/a/1403961
|
||||
|
||||
@@ -133,7 +133,7 @@ mod tests {
|
||||
fn all_variants() {
|
||||
// Static check
|
||||
let mut variants = IdCategory::all_variants();
|
||||
assert_eq!(variants.len(), 6);
|
||||
assert_eq!(variants.len(), 7);
|
||||
assert_eq!(variants.pop_first(), Some(IdCategory::MediaFile));
|
||||
assert_eq!(variants.pop_first(), Some(IdCategory::LipsyncAnimationResult));
|
||||
assert_eq!(variants.pop_first(), Some(IdCategory::VoiceConversionResult));
|
||||
|
||||
@@ -18,7 +18,7 @@ serde = "1.0.125"
|
||||
serde_derive = "1.0.125"
|
||||
|
||||
# Random
|
||||
rand = "0.8.3"
|
||||
rand = "0.8.5"
|
||||
|
||||
# MySql Database
|
||||
# "offline" supports typesafe builds without a live database
|
||||
@@ -28,6 +28,8 @@ sqlx = { version = "0.7.2", features = [ "mysql", "runtime-tokio", "tls-rustls",
|
||||
sqlx-core = { version = "0.7.2" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
|
||||
utoipa = { version = "4", features = ["actix_extras"] }
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
# Enum utilities
|
||||
|
||||
@@ -4,9 +4,10 @@ use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::prefixes::TokenPrefix;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// The primary key for "generic" inference jobs.
|
||||
#[derive(Clone, PartialEq, Eq, sqlx::Type, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, PartialEq, Eq, sqlx::Type, Debug, Serialize, Deserialize,ToSchema)]
|
||||
#[sqlx(transparent)]
|
||||
pub struct InferenceJobToken(String);
|
||||
|
||||
|
||||
@@ -5,19 +5,14 @@ use sqlx::mysql::MySqlPoolOptions;
|
||||
use config::shared_constants::{DEFAULT_MYSQL_CONNECTION_STRING, DEFAULT_RUST_LOG};
|
||||
use errors::AnyhowResult;
|
||||
|
||||
|
||||
use crate::seeding::model_weights::seed_weights;
|
||||
use crate::seeding::model_weights::seed_weights_for_user_token;
|
||||
|
||||
use crate::bucket_clients::get_bucket_clients;
|
||||
use crate::cli_args::parse_cli_args;
|
||||
use crate::seeding::model_weights::seed_weights;
|
||||
use crate::seeding::tts_tacotron2::seed_tts_tacotron2;
|
||||
|
||||
use crate::seeding::users::seed_user_accounts;
|
||||
use crate::seeding::voice_conversion::seed_voice_conversion;
|
||||
use crate::seeding::zero_shot_tts::seed_zero_shot_tts;
|
||||
|
||||
|
||||
pub mod bucket_clients;
|
||||
|
||||
pub mod cli_args;
|
||||
|
||||
@@ -21,7 +21,7 @@ errors = { path = "../../lib/errors" }
|
||||
# External
|
||||
log = "0.4.20"
|
||||
once_cell = "1.18.0"
|
||||
rand = "0.8.1"
|
||||
rand = "0.8.5"
|
||||
regex = "1.10.0"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
[package]
|
||||
name = "collections"
|
||||
edition = "2018"
|
||||
version = "0.0.1"
|
||||
authors = [
|
||||
"Brandon Thomas <bt@brand.io>",
|
||||
"Brandon Thomas <echelon@gmail.com>",
|
||||
]
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
# NB: Public "collections" crate is not yet taken (!!), so we're fine to use this internally for now.
|
||||
name = "collections"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
# Internal
|
||||
errors = { path = "../errors" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
|
||||
# External
|
||||
# KEEP THIS TO A MINIMUM OR NIL.
|
||||
rand = "0.8.5"
|
||||
|
||||
[dev-dependencies]
|
||||
# None yet
|
||||
@@ -0,0 +1,22 @@
|
||||
//! collections
|
||||
//!
|
||||
//! The purpose of this library is to provide "extra" data structures or utilities related to
|
||||
//! data structures. There should be minimal dependency introduction here.
|
||||
//!
|
||||
|
||||
// Never allow these
|
||||
#![forbid(private_in_public)]
|
||||
#![forbid(unused_must_use)] // NB: It's unsafe to not close/check some things
|
||||
|
||||
// Okay to toggle
|
||||
#![forbid(unreachable_patterns)]
|
||||
#![forbid(unused_imports)]
|
||||
#![forbid(unused_mut)]
|
||||
#![forbid(unused_variables)]
|
||||
|
||||
// Always allow
|
||||
#![allow(dead_code)]
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
pub mod multiple_random_from_vec;
|
||||
pub mod random_from_vec;
|
||||
+1
-1
@@ -12,7 +12,7 @@ pub fn multiple_random_from_vec<T>(vec: &Vec<T>, amount: usize) -> Vec<&T> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::collections::multiple_random_from_vec::multiple_random_from_vec;
|
||||
use crate::multiple_random_from_vec::multiple_random_from_vec;
|
||||
|
||||
#[test]
|
||||
fn pulls_item_from_vec() {
|
||||
+1
-1
@@ -7,7 +7,7 @@ pub fn random_from_vec<T>(vec: &Vec<T>) -> Option<&T> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::collections::random_from_vec::random_from_vec;
|
||||
use crate::random_from_vec::random_from_vec;
|
||||
|
||||
#[test]
|
||||
fn pulls_item_from_vec() {
|
||||
@@ -15,7 +15,7 @@ name = "crockford"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
rand = "0.8.3"
|
||||
rand = "0.8.5"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -17,7 +17,7 @@ path = "src/lib.rs"
|
||||
# External
|
||||
anyhow = "1.0.75"
|
||||
once_cell = "1.18.0"
|
||||
rand = "0.8.3"
|
||||
rand = "0.8.5"
|
||||
uuid = { version = "0.8.2", features = ["v4"] }
|
||||
log = "0.4.14"
|
||||
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
pub mod multiple_random_from_vec;
|
||||
pub mod random_from_vec;
|
||||
@@ -1,15 +0,0 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use anyhow::bail;
|
||||
|
||||
use crate::anyhow_result::AnyhowResult;
|
||||
|
||||
pub fn check_directory_exists(path: &PathBuf) -> AnyhowResult<()> {
|
||||
if !path.exists() {
|
||||
bail!("Path doesn't exist: {:?}", path);
|
||||
}
|
||||
if !path.is_dir() {
|
||||
bail!("Path isn't a directory: {:?}", path);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
pub mod check_directory_exists;
|
||||
pub mod check_file_exists;
|
||||
pub mod safe_delete_possible_temp_file;
|
||||
pub mod safe_delete_temp_directory;
|
||||
pub mod safe_delete_temp_file;
|
||||
@@ -1,7 +1,5 @@
|
||||
pub mod anyhow_result;
|
||||
pub mod collections;
|
||||
pub mod files;
|
||||
pub mod filesystem;
|
||||
pub mod i18n;
|
||||
pub mod numerics;
|
||||
pub mod thread;
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
pub mod random_crockford_token;
|
||||
pub mod random_prefix_crockford_token;
|
||||
pub mod random_uuid;
|
||||
@@ -1,100 +0,0 @@
|
||||
use anyhow::anyhow;
|
||||
use rand::Rng;
|
||||
|
||||
use crate::anyhow_result::AnyhowResult;
|
||||
|
||||
// Crockford characters
|
||||
const CROCKFORD_UPPERCASE_CHARSET: &[u8] = b"0123456789ABCDEFGHJKMNPQRSTVWXYZ";
|
||||
|
||||
const CROCKFORD_LOWERCASE_CHARSET: &[u8] = b"0123456789abcdefghjkmnpqrstvwxyz";
|
||||
|
||||
// Random part can't be any less than this.
|
||||
const MIN_ENTROPY_LENGTH : usize = 8;
|
||||
|
||||
#[deprecated(note = "see internal 'crockford' and 'token' crates")]
|
||||
pub fn random_prefix_crockford_token(prefix: &str, length: usize, uppercase: bool) -> AnyhowResult<String> {
|
||||
let mut prefix = prefix.trim().to_string();
|
||||
|
||||
if prefix.is_empty() {
|
||||
return Err(anyhow!("prefix not set; use other crockford functions"));
|
||||
}
|
||||
|
||||
if !prefix.ends_with(":") {
|
||||
prefix = format!("{}:", prefix);
|
||||
}
|
||||
|
||||
let entropy_length : usize = length.saturating_sub(prefix.len());
|
||||
|
||||
if entropy_length < MIN_ENTROPY_LENGTH {
|
||||
return Err(anyhow!("not enough entropy in token"));
|
||||
}
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let charset = if uppercase { CROCKFORD_UPPERCASE_CHARSET } else { CROCKFORD_LOWERCASE_CHARSET };
|
||||
|
||||
let entropy_part: String = (0..entropy_length)
|
||||
.map(|_| {
|
||||
let idx = rng.gen_range(0..charset.len());
|
||||
charset[idx] as char
|
||||
})
|
||||
.collect();
|
||||
|
||||
let token = format!("{}{}", prefix, entropy_part);
|
||||
Ok(token)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::token::random_prefix_crockford_token::random_prefix_crockford_token;
|
||||
|
||||
#[test]
|
||||
fn no_prefix_error() {
|
||||
assert!(random_prefix_crockford_token("", 0, false).is_err());
|
||||
assert!(random_prefix_crockford_token("", 10, false).is_err());
|
||||
assert!(random_prefix_crockford_token("", 32, false).is_err());
|
||||
assert!(random_prefix_crockford_token("", 0, true).is_err());
|
||||
assert!(random_prefix_crockford_token("", 10, true).is_err());
|
||||
assert!(random_prefix_crockford_token("", 32, true).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_enough_entropy_error() {
|
||||
assert!(random_prefix_crockford_token("foo", 0, false).is_err());
|
||||
assert!(random_prefix_crockford_token("foo", 5, false).is_err());
|
||||
assert!(random_prefix_crockford_token("foo", 11, false).is_err());
|
||||
assert!(random_prefix_crockford_token("foo:", 11, false).is_err());
|
||||
assert!(random_prefix_crockford_token("foo", 0, true).is_err());
|
||||
assert!(random_prefix_crockford_token("foo", 5, true).is_err());
|
||||
assert!(random_prefix_crockford_token("foo", 11, true).is_err());
|
||||
assert!(random_prefix_crockford_token("foo:", 11, true).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn starts_with() {
|
||||
assert!(random_prefix_crockford_token("w", 10, false).unwrap().starts_with("w:"));
|
||||
assert!(random_prefix_crockford_token("w", 10, false).unwrap().starts_with("w:"));
|
||||
assert!(random_prefix_crockford_token("prefix", 16, false).unwrap().starts_with("prefix:"));
|
||||
assert!(random_prefix_crockford_token("prefix:", 16, false).unwrap().starts_with("prefix:"));
|
||||
assert!(random_prefix_crockford_token("w", 10, true).unwrap().starts_with("w:"));
|
||||
assert!(random_prefix_crockford_token("w", 10, true).unwrap().starts_with("w:"));
|
||||
assert!(random_prefix_crockford_token("prefix", 16, true).unwrap().starts_with("prefix:"));
|
||||
assert!(random_prefix_crockford_token("prefix:", 16, true).unwrap().starts_with("prefix:"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn length() {
|
||||
assert_eq!(random_prefix_crockford_token("w", 10, false).unwrap().len(), 10);
|
||||
assert_eq!(random_prefix_crockford_token("w:", 10, false).unwrap().len(), 10);
|
||||
assert_eq!(random_prefix_crockford_token("prefix", 16, false).unwrap().len(), 16);
|
||||
assert_eq!(random_prefix_crockford_token("prefix:", 16, false).unwrap().len(), 16);
|
||||
assert_eq!(random_prefix_crockford_token("asdf:", 32, false).unwrap().len(), 32);
|
||||
assert_eq!(random_prefix_crockford_token("asdf", 32, false).unwrap().len(), 32);
|
||||
assert_eq!(random_prefix_crockford_token("w", 10, true).unwrap().len(), 10);
|
||||
assert_eq!(random_prefix_crockford_token("w:", 10, true).unwrap().len(), 10);
|
||||
assert_eq!(random_prefix_crockford_token("prefix", 16, true).unwrap().len(), 16);
|
||||
assert_eq!(random_prefix_crockford_token("prefix:", 16, true).unwrap().len(), 16);
|
||||
assert_eq!(random_prefix_crockford_token("asdf:", 32, true).unwrap().len(), 32);
|
||||
assert_eq!(random_prefix_crockford_token("asdf", 32, true).unwrap().len(), 32);
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ storyteller_root = { path = "../storyteller_root" }
|
||||
|
||||
# External
|
||||
dotenv = "0.15.0"
|
||||
env_logger = "0.10.0"
|
||||
env_logger = "0.10.1"
|
||||
log = "0.4.14"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ path = "src/lib.rs"
|
||||
# Internal
|
||||
errors = { path = "../../errors" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../../../my-workspace-hack" }
|
||||
log = "0.4.20"
|
||||
|
||||
# External
|
||||
# KEEP THIS TO A MINIMUM OR NIL.
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
use std::path::Path;
|
||||
|
||||
use errors::{AnyhowResult, bail};
|
||||
|
||||
pub fn check_directory_exists<P: AsRef<Path>>(path: P) -> AnyhowResult<()> {
|
||||
let check_path = path.as_ref();
|
||||
|
||||
if !check_path.exists() {
|
||||
bail!("Path doesn't exist: {:?}", check_path);
|
||||
}
|
||||
if !check_path.is_dir() {
|
||||
bail!("Path isn't a directory: {:?}", check_path);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
+2
-3
@@ -1,8 +1,7 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use anyhow::bail;
|
||||
|
||||
use crate::anyhow_result::AnyhowResult;
|
||||
use errors::AnyhowResult;
|
||||
use errors::bail;
|
||||
|
||||
pub fn check_file_exists(path: &PathBuf) -> AnyhowResult<()> {
|
||||
if !path.exists() {
|
||||
@@ -7,6 +7,7 @@ use errors::{anyhow, AnyhowResult};
|
||||
pub fn file_size<P: AsRef<Path>>(filename: P) -> AnyhowResult<u64> {
|
||||
let metadata = std::fs::metadata(filename.as_ref())?;
|
||||
|
||||
// TODO(bt,2023-11-29): Return io::Result and errors here.
|
||||
if !metadata.is_file() {
|
||||
Err(anyhow!("path {:?} is not a file", filename.as_ref()))
|
||||
} else if metadata.is_symlink() {
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
|
||||
// Nearly a third of `ErrorKind` is nightly rust, so we're going to have to match on
|
||||
// unix error codes until the rest of the ErrorKind enum variants are stable.
|
||||
// The error codes are maintained in sys/unix/mod.rs - decode_error_kind(i32)
|
||||
|
||||
const E_FILESYSTEM_QUOTA_EXCEEDED : i32 = 122; // pub const EDQUOT: ::c_int = 122;
|
||||
const E_STORAGE_FULL : i32 = 28; // pub const ENOSPC: ::c_int = 28;
|
||||
|
||||
/// Reports if an io::Error was caused by the filesystem being full.
|
||||
pub fn is_filesystem_full_error(err: &std::io::Error) -> bool {
|
||||
match err.raw_os_error() {
|
||||
Some(E_FILESYSTEM_QUOTA_EXCEEDED) => true,
|
||||
Some(E_STORAGE_FULL) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@@ -18,11 +18,17 @@
|
||||
#![allow(dead_code)]
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
pub mod check_file_exists;
|
||||
pub mod create_dir_all_if_missing;
|
||||
pub mod directory_exists;
|
||||
pub mod file_exists;
|
||||
pub mod file_read_bytes;
|
||||
pub mod file_size;
|
||||
pub mod filename_concat;
|
||||
pub mod is_filesystem_full_error;
|
||||
pub mod path_to_string;
|
||||
pub mod rename_across_devices;
|
||||
pub mod check_directory_exists;
|
||||
pub mod safe_delete_temp_file;
|
||||
pub mod safe_delete_possible_temp_file;
|
||||
pub mod safe_delete_temp_directory;
|
||||
|
||||
@@ -1,30 +1,80 @@
|
||||
use std::error::Error;
|
||||
use std::fmt;
|
||||
use std::path::Path;
|
||||
|
||||
use log::error;
|
||||
|
||||
use crate::is_filesystem_full_error::is_filesystem_full_error;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum RenameError {
|
||||
StorageFull,
|
||||
IoError(std::io::Error),
|
||||
}
|
||||
|
||||
impl Error for RenameError {}
|
||||
|
||||
impl fmt::Display for RenameError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
RenameError::StorageFull => write!(f, "RenameError: storage is full"),
|
||||
RenameError::IoError(err) => write!(f, "{:?}", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for RenameError {
|
||||
fn from(error: std::io::Error) -> Self {
|
||||
RenameError::IoError(error)
|
||||
}
|
||||
}
|
||||
|
||||
/// Rename a file.
|
||||
/// Ordinary rename will fail in Linux if it is across physical devices.
|
||||
/// This function will perform a copy followed by delete in that case.
|
||||
pub fn rename_across_devices<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> std::io::Result<()> {
|
||||
/// In both cases, this function will overwrite the destination if it already exists.
|
||||
pub fn rename_across_devices<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> Result<(), RenameError> {
|
||||
let result = std::fs::rename(&from, &to);
|
||||
|
||||
let err = match result.as_ref() {
|
||||
let err = match result {
|
||||
Ok(_) => return Ok(()), // Rename succeeded.
|
||||
Err(err) => err,
|
||||
};
|
||||
|
||||
// Nearly a third of `ErrorKind` is nightly rust, so we're going to have to match on
|
||||
// unix error codes until the rest of the ErrorKind enum variants are stable.
|
||||
// The error codes are maintained in sys/unix/mod.rs - decode_error_kind(i32)
|
||||
const E_CROSSES_DEVICES : i32 = 18; // pub const EXDEV: ::c_int = 18;
|
||||
|
||||
if is_filesystem_full_error(&err) {
|
||||
error!("Filesystem is full during rename.");
|
||||
return Err(RenameError::StorageFull);
|
||||
}
|
||||
|
||||
match err.raw_os_error() {
|
||||
Some(18) => {
|
||||
// NO-OP: pass-through
|
||||
// NB: We can clean this up in the future when `err.kind() == ErrorKind::CrossDevices`
|
||||
// stabilizes. For now we can assume code "18" means we're trying to rename across devices.
|
||||
Some(E_CROSSES_DEVICES) => {
|
||||
// NB: Fall through.
|
||||
}
|
||||
_ => {
|
||||
// Something else happened. Return original error.
|
||||
return result;
|
||||
return Err(RenameError::IoError(err));
|
||||
}
|
||||
}
|
||||
|
||||
let _num_bytes = std::fs::copy(&from, &to)?;
|
||||
// NB: In production we've seen std::fs::copy silently succeed, yet copy zero bytes. The reason
|
||||
// is more than likely that the filesystem is full. We'll check the number of copied bytes to
|
||||
// confirm. Moreover, the Rust docs say wrt std::fs::copy, "On success, the total number of bytes
|
||||
// copied is returned and it is equal to the length of the to file as reported by metadata."
|
||||
let original_file_size = std::fs::metadata(from.as_ref())?.len();
|
||||
|
||||
let num_bytes_copied = std::fs::copy(&from, &to)?;
|
||||
|
||||
if num_bytes_copied != original_file_size {
|
||||
error!("Filesystem is full during copy. Not all bytes copied.");
|
||||
return Err(RenameError::StorageFull);
|
||||
}
|
||||
|
||||
// An emulated "rename" would delete the source file.
|
||||
std::fs::remove_file(&from)?;
|
||||
|
||||
Ok(())
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
use std::path::Path;
|
||||
|
||||
use crate::filesystem::safe_delete_temp_file::safe_delete_temp_file;
|
||||
use crate::safe_delete_temp_file::safe_delete_temp_file;
|
||||
|
||||
pub fn safe_delete_possible_temp_file<P: AsRef<Path>>(maybe_file_path: Option<P>) {
|
||||
if let Some(file_path) = maybe_file_path {
|
||||
@@ -15,7 +15,7 @@ path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
dotenv = "0.15.0"
|
||||
env_logger = "0.10.0"
|
||||
env_logger = "0.10.1"
|
||||
log = "0.4.20"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
|
||||
|
||||
+9
@@ -24,6 +24,8 @@ pub struct InsertGenericInferenceArgs<'a> {
|
||||
|
||||
pub maybe_raw_inference_text: Option<&'a str>,
|
||||
|
||||
pub maybe_max_duration_seconds: Option<i32>,
|
||||
|
||||
pub maybe_inference_args: Option<GenericInferenceArgs>,
|
||||
|
||||
pub maybe_creator_user_token: Option<&'a UserToken>,
|
||||
@@ -54,6 +56,11 @@ pub async fn insert_generic_inference_job(args: InsertGenericInferenceArgs<'_>)
|
||||
routing_tag
|
||||
});
|
||||
|
||||
// This only applies to certain types of inference.
|
||||
// "0" is the default value, typically 12 seconds for TTS.
|
||||
// "-1" means "unlimited"
|
||||
let max_duration_seconds = args.maybe_max_duration_seconds.unwrap_or(0);
|
||||
|
||||
let query = sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO generic_inference_jobs
|
||||
@@ -80,6 +87,7 @@ SET
|
||||
|
||||
priority_level = ?,
|
||||
is_keepalive_required = ?,
|
||||
max_duration_seconds = ?,
|
||||
|
||||
is_debug_request = ?,
|
||||
maybe_routing_tag = ?,
|
||||
@@ -109,6 +117,7 @@ SET
|
||||
|
||||
args.priority_level,
|
||||
args.requires_keepalive,
|
||||
max_duration_seconds,
|
||||
|
||||
args.is_debug_request,
|
||||
maybe_routing_tag,
|
||||
|
||||
+157
@@ -0,0 +1,157 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
use anyhow::anyhow;
|
||||
use sqlx::{MySql, MySqlPool, QueryBuilder};
|
||||
|
||||
use enums::by_table::generic_inference_jobs::inference_category::InferenceCategory;
|
||||
use enums::by_table::generic_inference_jobs::inference_model_type::InferenceModelType;
|
||||
use enums::common::job_status::JobStatus;
|
||||
use errors::AnyhowResult;
|
||||
|
||||
/// Only certain job statuses should be modified.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum KillableStatus {
|
||||
Failed,
|
||||
Pending,
|
||||
Started,
|
||||
}
|
||||
|
||||
/// Target everything, by job category, or by model type.
|
||||
#[derive(Clone)]
|
||||
pub enum KillableTarget {
|
||||
AllJobs,
|
||||
Category(InferenceCategory),
|
||||
ModelType(InferenceModelType),
|
||||
}
|
||||
|
||||
pub struct KillGenericInferenceJobsArgs<'a> {
|
||||
pub job_statuses: HashSet<KillableStatus>,
|
||||
pub target: KillableTarget,
|
||||
pub maybe_priority_or_lower: Option<u8>,
|
||||
pub mysql_pool: &'a MySqlPool,
|
||||
}
|
||||
|
||||
pub async fn kill_generic_inference_jobs(args: KillGenericInferenceJobsArgs<'_>) -> AnyhowResult<()> {
|
||||
let mut query = query_builder(
|
||||
args.job_statuses,
|
||||
args.target,
|
||||
args.maybe_priority_or_lower
|
||||
);
|
||||
|
||||
let query = query.build();
|
||||
|
||||
let result = query.execute(args.mysql_pool).await;
|
||||
|
||||
match result {
|
||||
Err(err) => {
|
||||
Err(anyhow!("error with query: {:?}", err))
|
||||
},
|
||||
Ok(_r) => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
fn query_builder(
|
||||
job_statuses: HashSet<KillableStatus>,
|
||||
target: KillableTarget,
|
||||
maybe_priority_or_lower: Option<u8>,
|
||||
) -> QueryBuilder<'static, MySql> {
|
||||
|
||||
// NB: Query cannot be statically checked by sqlx
|
||||
let mut query_builder: QueryBuilder<MySql> = QueryBuilder::new(
|
||||
r#"
|
||||
UPDATE generic_inference_jobs
|
||||
SET status='cancelled_by_system'
|
||||
WHERE status IN(
|
||||
"#
|
||||
);
|
||||
|
||||
let job_statuses = job_statuses.into_iter()
|
||||
.map(|status| match status {
|
||||
KillableStatus::Failed => JobStatus::AttemptFailed.to_str(),
|
||||
KillableStatus::Pending => JobStatus::Pending.to_str(),
|
||||
KillableStatus::Started => JobStatus::Started.to_str(),
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// NB: Syntax will be wrong if list has zero length
|
||||
let mut separated = query_builder.separated(", ");
|
||||
for value_type in job_statuses.into_iter() {
|
||||
separated.push_bind(value_type);
|
||||
}
|
||||
separated.push_unseparated(") ");
|
||||
|
||||
if let Some(priority) = maybe_priority_or_lower {
|
||||
query_builder.push(format!(" AND priority_level <= {priority} "));
|
||||
}
|
||||
|
||||
match target {
|
||||
KillableTarget::AllJobs => {
|
||||
// No need to modify query.
|
||||
}
|
||||
KillableTarget::Category(category) => {
|
||||
query_builder.push(" AND inference_category = ");
|
||||
query_builder.push_bind(category);
|
||||
}
|
||||
KillableTarget::ModelType(model_type) => {
|
||||
query_builder.push(" AND maybe_model_type = ");
|
||||
query_builder.push_bind(model_type);
|
||||
}
|
||||
}
|
||||
|
||||
query_builder
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::collections::HashSet;
|
||||
|
||||
use regex::Regex;
|
||||
|
||||
use enums::by_table::generic_inference_jobs::inference_category::InferenceCategory;
|
||||
use enums::by_table::generic_inference_jobs::inference_model_type::InferenceModelType;
|
||||
|
||||
use crate::queries::generic_inference::web::kill_generic_inference_jobs::{KillableStatus, KillableTarget, query_builder};
|
||||
|
||||
fn cleanup_query(query: &str) -> String {
|
||||
let regex = Regex::new(r#"\s+"#).unwrap();
|
||||
let result = regex.replace_all(query, " ").trim().to_string();
|
||||
result
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_statuses() {
|
||||
let statuses = HashSet::from([KillableStatus::Failed]);
|
||||
let builder = query_builder(statuses, KillableTarget::AllJobs, None);
|
||||
let query = cleanup_query(&builder.into_sql());
|
||||
assert_eq!(query, "UPDATE generic_inference_jobs SET status='cancelled_by_system' WHERE status IN( ?)".to_string());
|
||||
|
||||
let statuses = HashSet::from([KillableStatus::Failed, KillableStatus::Pending, KillableStatus::Started]);
|
||||
let builder = query_builder(statuses, KillableTarget::AllJobs, None);
|
||||
let query = cleanup_query(&builder.into_sql());
|
||||
assert_eq!(query, "UPDATE generic_inference_jobs SET status='cancelled_by_system' WHERE status IN( ?, ?, ?)".to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_priority() {
|
||||
let statuses = HashSet::from([KillableStatus::Failed]);
|
||||
let builder = query_builder(statuses, KillableTarget::AllJobs, Some(10));
|
||||
let query = cleanup_query(&builder.into_sql());
|
||||
assert_eq!(query, "UPDATE generic_inference_jobs SET status='cancelled_by_system' WHERE status IN( ?) AND priority_level <= 10".to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_category_target() {
|
||||
let statuses = HashSet::from([KillableStatus::Failed]);
|
||||
let builder = query_builder(statuses, KillableTarget::Category(InferenceCategory::LipsyncAnimation), None);
|
||||
let query = cleanup_query(&builder.into_sql());
|
||||
assert_eq!(query, "UPDATE generic_inference_jobs SET status='cancelled_by_system' WHERE status IN( ?) AND inference_category = ?".to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_model_target() {
|
||||
let statuses = HashSet::from([KillableStatus::Failed]);
|
||||
let builder = query_builder(statuses, KillableTarget::ModelType(InferenceModelType::RvcV2), None);
|
||||
let query = cleanup_query(&builder.into_sql());
|
||||
assert_eq!(query, "UPDATE generic_inference_jobs SET status='cancelled_by_system' WHERE status IN( ?) AND maybe_model_type = ?".to_string());
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
pub mod get_inference_job_status;
|
||||
pub mod get_pending_inference_job_count;
|
||||
pub mod insert_generic_inference_job;
|
||||
pub mod kill_generic_inference_jobs;
|
||||
|
||||
@@ -157,7 +157,7 @@ async fn select_include_deleted(
|
||||
"#,
|
||||
weight_token.as_str()
|
||||
)
|
||||
.fetch_one(mysql_connection).await
|
||||
.fetch_one(&mut **mysql_connection).await
|
||||
}
|
||||
|
||||
async fn select_without_deleted(
|
||||
@@ -207,7 +207,7 @@ async fn select_without_deleted(
|
||||
"#,
|
||||
weight_token.as_str()
|
||||
)
|
||||
.fetch_one(mysql_connection).await
|
||||
.fetch_one(&mut **mysql_connection).await
|
||||
}
|
||||
|
||||
// RawWeight is the struct that is returned from the database in raw form.
|
||||
|
||||
@@ -1,19 +1,13 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use sqlx::{Acquire, MySqlConnection, MySqlPool};
|
||||
|
||||
use anyhow::anyhow;
|
||||
use chrono::{ DateTime, Utc };
|
||||
use enums::by_table::model_weights::weights_types;
|
||||
use log::{ info, warn };
|
||||
use sqlx::{ MySql, MySqlPool, query, Acquire, MySqlConnection };
|
||||
use sqlx::pool::PoolConnection;
|
||||
|
||||
use enums::by_table::model_weights::{
|
||||
weights_category::WeightsCategory,
|
||||
weights_types::WeightsType,
|
||||
};
|
||||
use enums::common::visibility::Visibility;
|
||||
use errors::AnyhowResult;
|
||||
use tokens::tokens::model_weights::ModelWeightToken;
|
||||
|
||||
use enums::by_table::model_weights::{
|
||||
weights_types::WeightsType,
|
||||
weights_category::WeightsCategory,
|
||||
};
|
||||
use tokens::tokens::users::UserToken;
|
||||
|
||||
#[derive(Serialize)]
|
||||
@@ -136,7 +130,7 @@ async fn get_raw_weights_by_creator_username(
|
||||
"#,
|
||||
creator_username).fetch_all(connection)
|
||||
.await?;
|
||||
return Ok(raw_weights);
|
||||
Ok(raw_weights)
|
||||
} else {
|
||||
let raw_weights: Vec<RawWeightJoinUser> = sqlx::query_as!(
|
||||
RawWeightJoinUser,
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
use anyhow::anyhow;
|
||||
use sqlx::MySqlPool;
|
||||
|
||||
use log::info;
|
||||
use sqlx::mysql::MySqlPoolOptions;
|
||||
|
||||
use enums::common::visibility::Visibility;
|
||||
use errors::AnyhowResult;
|
||||
use tokens::tokens::model_weights::ModelWeightToken;
|
||||
|
||||
use config::shared_constants::{DEFAULT_MYSQL_CONNECTION_STRING, DEFAULT_RUST_LOG};
|
||||
|
||||
pub struct UpdateWeightArgs<'a> {
|
||||
pub weight_token: &'a ModelWeightToken,
|
||||
pub title: Option<&'a str>,
|
||||
@@ -58,13 +53,13 @@ pub async fn update_weights(args: UpdateWeightArgs<'_>) -> AnyhowResult<()> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use tokio;
|
||||
// Template
|
||||
// Template
|
||||
use sqlx::mysql::MySqlPoolOptions;
|
||||
use tokio;
|
||||
|
||||
use config::shared_constants::{DEFAULT_MYSQL_CONNECTION_STRING};
|
||||
use config::shared_constants::DEFAULT_MYSQL_CONNECTION_STRING;
|
||||
use errors::AnyhowResult;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_update_weights() -> AnyhowResult<()> {
|
||||
let db_connection_string = DEFAULT_MYSQL_CONNECTION_STRING;
|
||||
|
||||
@@ -26,5 +26,5 @@ serde_derive = "1.0.125"
|
||||
serde_json = "1.0.108"
|
||||
|
||||
# TODO: Get rid of in favor of std::time
|
||||
time = "0.2.26"
|
||||
time = "0.3.30"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
|
||||
@@ -30,7 +30,7 @@ chrono = { version = "=0.4.22", features = ["serde"] }
|
||||
dotenv = "0.15.0"
|
||||
hostname = "0.3.1"
|
||||
log = "0.4.14"
|
||||
rand = "0.8.3"
|
||||
rand = "0.8.5"
|
||||
|
||||
# MySql Database
|
||||
# "offline" supports typesafe builds without a live database
|
||||
|
||||
@@ -6,7 +6,7 @@ use tempdir::TempDir;
|
||||
|
||||
use config::is_bad_download_url::is_bad_download_url;
|
||||
use container_common::anyhow_result::AnyhowResult;
|
||||
use container_common::filesystem::safe_delete_temp_directory::safe_delete_temp_directory;
|
||||
use filesys::safe_delete_temp_directory::safe_delete_temp_directory;
|
||||
use jobs_common::redis_job_status_logger::RedisJobStatusLogger;
|
||||
use mysql_queries::queries::generic_download::job::list_available_generic_download_jobs::AvailableDownloadJob;
|
||||
use mysql_queries::queries::generic_download::job::mark_generic_download_job_done::mark_generic_download_job_done;
|
||||
|
||||
+3
-3
@@ -6,12 +6,12 @@ use anyhow::anyhow;
|
||||
use log::{info, warn};
|
||||
use tempdir::TempDir;
|
||||
|
||||
use container_common::filesystem::check_file_exists::check_file_exists;
|
||||
use container_common::filesystem::safe_delete_temp_directory::safe_delete_temp_directory;
|
||||
use container_common::filesystem::safe_delete_temp_file::safe_delete_temp_file;
|
||||
use enums::by_table::tts_models::tts_model_type::TtsModelType;
|
||||
use enums::common::visibility::Visibility;
|
||||
use errors::AnyhowResult;
|
||||
use filesys::check_file_exists::check_file_exists;
|
||||
use filesys::safe_delete_temp_directory::safe_delete_temp_directory;
|
||||
use filesys::safe_delete_temp_file::safe_delete_temp_file;
|
||||
use hashing::sha256::sha256_hash_file::sha256_hash_file;
|
||||
use jobs_common::redis_job_status_logger::RedisJobStatusLogger;
|
||||
use mysql_queries::queries::generic_download::job::list_available_generic_download_jobs::AvailableDownloadJob;
|
||||
|
||||
@@ -4,14 +4,14 @@ use anyhow::anyhow;
|
||||
use log::{error, info, warn};
|
||||
use tempdir::TempDir;
|
||||
|
||||
use container_common::filesystem::check_file_exists::check_file_exists;
|
||||
use container_common::filesystem::safe_delete_temp_directory::safe_delete_temp_directory;
|
||||
use container_common::filesystem::safe_delete_temp_file::safe_delete_temp_file;
|
||||
use enums::by_table::tts_models::tts_model_type::TtsModelType;
|
||||
use enums::common::visibility::Visibility;
|
||||
use errors::AnyhowResult;
|
||||
use filesys::check_file_exists::check_file_exists;
|
||||
use filesys::file_size::file_size;
|
||||
use filesys::filename_concat::filename_concat;
|
||||
use filesys::safe_delete_temp_directory::safe_delete_temp_directory;
|
||||
use filesys::safe_delete_temp_file::safe_delete_temp_file;
|
||||
use hashing::sha256::sha256_hash_file::sha256_hash_file;
|
||||
use jobs_common::redis_job_status_logger::RedisJobStatusLogger;
|
||||
use mysql_queries::queries::generic_download::job::list_available_generic_download_jobs::AvailableDownloadJob;
|
||||
|
||||
+3
-3
@@ -6,11 +6,11 @@ use anyhow::anyhow;
|
||||
use log::{info, warn};
|
||||
use tempdir::TempDir;
|
||||
|
||||
use container_common::filesystem::check_file_exists::check_file_exists;
|
||||
use container_common::filesystem::safe_delete_temp_directory::safe_delete_temp_directory;
|
||||
use container_common::filesystem::safe_delete_temp_file::safe_delete_temp_file;
|
||||
use enums::common::vocoder_type::VocoderType;
|
||||
use errors::AnyhowResult;
|
||||
use filesys::check_file_exists::check_file_exists;
|
||||
use filesys::safe_delete_temp_directory::safe_delete_temp_directory;
|
||||
use filesys::safe_delete_temp_file::safe_delete_temp_file;
|
||||
use hashing::sha256::sha256_hash_file::sha256_hash_file;
|
||||
use jobs_common::redis_job_status_logger::RedisJobStatusLogger;
|
||||
use mysql_queries::queries::generic_download::job::list_available_generic_download_jobs::AvailableDownloadJob;
|
||||
|
||||
+3
-3
@@ -6,11 +6,11 @@ use anyhow::anyhow;
|
||||
use log::{info, warn};
|
||||
use tempdir::TempDir;
|
||||
|
||||
use container_common::filesystem::check_file_exists::check_file_exists;
|
||||
use container_common::filesystem::safe_delete_temp_directory::safe_delete_temp_directory;
|
||||
use container_common::filesystem::safe_delete_temp_file::safe_delete_temp_file;
|
||||
use enums::common::vocoder_type::VocoderType;
|
||||
use errors::AnyhowResult;
|
||||
use filesys::check_file_exists::check_file_exists;
|
||||
use filesys::safe_delete_temp_directory::safe_delete_temp_directory;
|
||||
use filesys::safe_delete_temp_file::safe_delete_temp_file;
|
||||
use hashing::sha256::sha256_hash_file::sha256_hash_file;
|
||||
use jobs_common::redis_job_status_logger::RedisJobStatusLogger;
|
||||
use mysql_queries::queries::generic_download::job::list_available_generic_download_jobs::AvailableDownloadJob;
|
||||
|
||||
+1
-1
@@ -3,8 +3,8 @@ use std::path::{Path, PathBuf};
|
||||
use log::{info, warn};
|
||||
use tempdir::TempDir;
|
||||
|
||||
use container_common::filesystem::safe_delete_temp_file::safe_delete_temp_file;
|
||||
use errors::AnyhowResult;
|
||||
use filesys::safe_delete_temp_file::safe_delete_temp_file;
|
||||
use mimetypes::mimetype_for_file::get_mimetype_for_file;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
||||
+1
-1
@@ -5,10 +5,10 @@ use log::info;
|
||||
use tempdir::TempDir;
|
||||
|
||||
use cloud_storage::bucket_client::BucketClient;
|
||||
use container_common::filesystem::safe_delete_temp_directory::safe_delete_temp_directory;
|
||||
use errors::AnyhowResult;
|
||||
use filesys::create_dir_all_if_missing::create_dir_all_if_missing;
|
||||
use filesys::file_exists::file_exists;
|
||||
use filesys::safe_delete_temp_directory::safe_delete_temp_directory;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PretrainedHubertModel {
|
||||
|
||||
+4
-4
@@ -4,15 +4,15 @@ use anyhow::anyhow;
|
||||
use log::{error, info, warn};
|
||||
use tempdir::TempDir;
|
||||
|
||||
use container_common::filesystem::check_file_exists::check_file_exists;
|
||||
use container_common::filesystem::safe_delete_possible_temp_file::safe_delete_possible_temp_file;
|
||||
use container_common::filesystem::safe_delete_temp_directory::safe_delete_temp_directory;
|
||||
use container_common::filesystem::safe_delete_temp_file::safe_delete_temp_file;
|
||||
use crockford::crockford_entropy_lower;
|
||||
use enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType;
|
||||
use enums::common::visibility::Visibility;
|
||||
use errors::AnyhowResult;
|
||||
use filesys::check_file_exists::check_file_exists;
|
||||
use filesys::file_size::file_size;
|
||||
use filesys::safe_delete_possible_temp_file::safe_delete_possible_temp_file;
|
||||
use filesys::safe_delete_temp_directory::safe_delete_temp_directory;
|
||||
use filesys::safe_delete_temp_file::safe_delete_temp_file;
|
||||
use jobs_common::redis_job_status_logger::RedisJobStatusLogger;
|
||||
use mysql_queries::queries::generic_download::job::list_available_generic_download_jobs::AvailableDownloadJob;
|
||||
use mysql_queries::queries::voice_conversion::models::insert_voice_conversion_model_from_download_job::{insert_voice_conversion_model_from_download_job, InsertVoiceConversionModelArgs};
|
||||
|
||||
+3
-3
@@ -4,13 +4,13 @@ use anyhow::anyhow;
|
||||
use log::{error, info, warn};
|
||||
use tempdir::TempDir;
|
||||
|
||||
use container_common::filesystem::check_file_exists::check_file_exists;
|
||||
use container_common::filesystem::safe_delete_temp_directory::safe_delete_temp_directory;
|
||||
use container_common::filesystem::safe_delete_temp_file::safe_delete_temp_file;
|
||||
use enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType;
|
||||
use enums::common::visibility::Visibility;
|
||||
use errors::AnyhowResult;
|
||||
use filesys::check_file_exists::check_file_exists;
|
||||
use filesys::file_size::file_size;
|
||||
use filesys::safe_delete_temp_directory::safe_delete_temp_directory;
|
||||
use filesys::safe_delete_temp_file::safe_delete_temp_file;
|
||||
use hashing::sha256::sha256_hash_file::sha256_hash_file;
|
||||
use jobs_common::redis_job_status_logger::RedisJobStatusLogger;
|
||||
use mysql_queries::queries::generic_download::job::list_available_generic_download_jobs::AvailableDownloadJob;
|
||||
|
||||
+3
-3
@@ -6,12 +6,12 @@ use anyhow::anyhow;
|
||||
use log::{info, warn};
|
||||
use tempdir::TempDir;
|
||||
|
||||
use container_common::filesystem::check_file_exists::check_file_exists;
|
||||
use container_common::filesystem::safe_delete_temp_directory::safe_delete_temp_directory;
|
||||
use container_common::filesystem::safe_delete_temp_file::safe_delete_temp_file;
|
||||
use enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType;
|
||||
use enums::common::visibility::Visibility;
|
||||
use errors::AnyhowResult;
|
||||
use filesys::check_file_exists::check_file_exists;
|
||||
use filesys::safe_delete_temp_directory::safe_delete_temp_directory;
|
||||
use filesys::safe_delete_temp_file::safe_delete_temp_file;
|
||||
use hashing::sha256::sha256_hash_file::sha256_hash_file;
|
||||
use jobs_common::redis_job_status_logger::RedisJobStatusLogger;
|
||||
use mysql_queries::queries::generic_download::job::list_available_generic_download_jobs::AvailableDownloadJob;
|
||||
|
||||
@@ -33,8 +33,8 @@ use cloud_storage::bucket_path_unifier::BucketPathUnifier;
|
||||
use config::common_env::CommonEnv;
|
||||
use config::shared_constants::DEFAULT_MYSQL_CONNECTION_STRING;
|
||||
use config::shared_constants::DEFAULT_RUST_LOG;
|
||||
use container_common::filesystem::check_directory_exists::check_directory_exists;
|
||||
use errors::AnyhowResult;
|
||||
use filesys::check_directory_exists::check_directory_exists;
|
||||
use google_drive_common::google_drive_download_command::GoogleDriveDownloadCommand;
|
||||
use mysql_queries::common_inputs::container_environment_arg::ContainerEnvironmentArg;
|
||||
use mysql_queries::mediators::badge_granter::BadgeGranter;
|
||||
|
||||
@@ -19,9 +19,9 @@ actix_helpers = { path = "../../../lib/actix_helpers" }
|
||||
bootstrap = { path = "../../../lib/bootstrap" }
|
||||
buckets = { path = "../../../_types/buckets" }
|
||||
cloud_storage = { path = "../../../lib/api_clients/cloud_storage" }
|
||||
collections = { path = "../../../lib/collections" }
|
||||
concurrency = { path = "../../../lib/concurrency" }
|
||||
config = { path = "../../../lib/deprecated/config" }
|
||||
container_common = { path = "../../../lib/deprecated/container_common" }
|
||||
easyenv = { path = "../../../lib/easyenv" }
|
||||
enums = { path = "../../../_types/enums" }
|
||||
errors = { path = "../../../lib/errors" }
|
||||
@@ -46,6 +46,7 @@ anyhow = "1.0.75"
|
||||
chrono = { version = "=0.4.22", features = ["serde"] }
|
||||
dotenv = "0.15.0"
|
||||
hostname = "0.3.1"
|
||||
lfu = "0.2.5"
|
||||
log = "0.4.14"
|
||||
once_cell = "1.18.0"
|
||||
subprocess = "0.2.9"
|
||||
|
||||
@@ -1,16 +1,25 @@
|
||||
use std::path::Path;
|
||||
|
||||
use log::warn;
|
||||
|
||||
use container_common::collections::multiple_random_from_vec::multiple_random_from_vec;
|
||||
use collections::multiple_random_from_vec::multiple_random_from_vec;
|
||||
use errors::AnyhowResult;
|
||||
use filesys::safe_delete_temp_file::safe_delete_temp_file;
|
||||
use jobs_common::semi_persistent_cache_dir::SemiPersistentCacheDir;
|
||||
|
||||
pub fn clear_full_filesystem(cache_dir: &SemiPersistentCacheDir) -> AnyhowResult<()> {
|
||||
warn!("Deleting cached VC models to free up disk space.");
|
||||
warn!("Deleting cached models to free up disk space.");
|
||||
|
||||
let model_dir = cache_dir.voice_conversion_model_directory();
|
||||
decimate_directory(cache_dir.custom_vocoder_model_directory())?;
|
||||
decimate_directory(cache_dir.tts_synthesizer_model_directory())?;
|
||||
decimate_directory(cache_dir.voice_conversion_model_directory())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn decimate_directory(path: &Path) -> AnyhowResult<()> {
|
||||
// TODO: When this is no longer sufficient, delete other types of locally-cached data.
|
||||
let paths = std::fs::read_dir(model_dir)?
|
||||
let paths = std::fs::read_dir(path)?
|
||||
.map(|res| res.map(|e| e.path()))
|
||||
.collect::<Result<Vec<_>, std::io::Error>>()?;
|
||||
|
||||
@@ -21,8 +30,8 @@ pub fn clear_full_filesystem(cache_dir: &SemiPersistentCacheDir) -> AnyhowResult
|
||||
for model_to_delete in models_to_delete {
|
||||
warn!("Deleting cached model file: {:?}", model_to_delete);
|
||||
|
||||
let full_model_path = cache_dir.voice_conversion_model_path(model_to_delete);
|
||||
std::fs::remove_file(full_model_path)?;
|
||||
let full_model_path = path.join(model_to_delete);
|
||||
safe_delete_temp_file(full_model_path);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
use std::path::PathBuf;
|
||||
|
||||
use anyhow::anyhow;
|
||||
use log::{info, warn};
|
||||
|
||||
use enums::by_table::generic_inference_jobs::inference_category::InferenceCategory;
|
||||
use enums::by_table::tts_models::tts_model_type::TtsModelType;
|
||||
use enums::by_table::voice_conversion_models::voice_conversion_model_type::VoiceConversionModelType;
|
||||
use errors::AnyhowResult;
|
||||
use filesys::file_exists::file_exists;
|
||||
use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob;
|
||||
use mysql_queries::queries::tts::tts_models::get_tts_model_for_inference_improved::{get_tts_model_for_inference_improved, TtsModelForInferenceRecord};
|
||||
use mysql_queries::queries::tts::tts_models::get_tts_model_for_inference_improved::{get_tts_model_for_inference_improved, TtsModelForInferenceError, TtsModelForInferenceRecord};
|
||||
use mysql_queries::queries::voice_conversion::inference::get_voice_conversion_model_for_inference::{get_voice_conversion_model_for_inference, VoiceConversionModelForInference};
|
||||
|
||||
use crate::job::job_loop::process_single_job_error::ProcessSingleJobError;
|
||||
use crate::job_dependencies::JobDependencies;
|
||||
|
||||
pub struct DependencyStatus {
|
||||
@@ -31,7 +32,7 @@ pub enum MaybeInferenceModel {
|
||||
VcModel(VoiceConversionModelForInference)
|
||||
}
|
||||
|
||||
pub async fn determine_dependency_status(job_dependencies: &JobDependencies, job: &AvailableInferenceJob) -> AnyhowResult<DependencyStatus> {
|
||||
pub async fn determine_dependency_status(job_dependencies: &JobDependencies, job: &AvailableInferenceJob) -> Result<DependencyStatus, ProcessSingleJobError> {
|
||||
let maybe_model = get_model_record_from_cacheable_query(job_dependencies, job).await?;
|
||||
let maybe_token_and_path = get_model_token_and_path(job_dependencies, &maybe_model);
|
||||
|
||||
@@ -105,10 +106,16 @@ fn get_model_token_and_path(job_dependencies: &JobDependencies, maybe_model: &Ma
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_model_record_from_cacheable_query(job_dependencies: &JobDependencies, job: &AvailableInferenceJob) -> AnyhowResult<MaybeInferenceModel> {
|
||||
async fn get_model_record_from_cacheable_query(job_dependencies: &JobDependencies, job: &AvailableInferenceJob) -> Result<MaybeInferenceModel, ProcessSingleJobError> {
|
||||
let model = match (job.inference_category, job.maybe_model_token.as_deref()) {
|
||||
(InferenceCategory::TextToSpeech, Some(token)) => {
|
||||
let maybe_model = job_dependencies.job.info.caches.tts_model_record_cache.copy_without_bump_if_unexpired(token.to_string())?;
|
||||
let maybe_model = job_dependencies
|
||||
.job
|
||||
.info
|
||||
.caches
|
||||
.tts_model_record_cache
|
||||
.copy_without_bump_if_unexpired(token.to_string())
|
||||
.map_err(|err| ProcessSingleJobError::from_anyhow_error(err))?;
|
||||
|
||||
match maybe_model {
|
||||
Some(model) => MaybeInferenceModel::TtsModel(model),
|
||||
@@ -116,22 +123,36 @@ async fn get_model_record_from_cacheable_query(job_dependencies: &JobDependencie
|
||||
let maybe_tts_model = get_tts_model_for_inference_improved(
|
||||
&job_dependencies.db.mysql_pool, token)
|
||||
.await
|
||||
.map_err(|err| anyhow!("database error: {:?}", err))?;
|
||||
.map_err(|err| match err {
|
||||
TtsModelForInferenceError::ModelDeleted => ProcessSingleJobError::ModelDeleted,
|
||||
_ => ProcessSingleJobError::Other(anyhow!("database error: {:?}", err))
|
||||
})?;
|
||||
|
||||
match maybe_tts_model {
|
||||
None => MaybeInferenceModel::None,
|
||||
Some(model) => {
|
||||
let token = token.to_string();
|
||||
let _r = job_dependencies.job.info.caches.tts_model_record_cache.store_copy(&token, &model)?;
|
||||
let _r = job_dependencies
|
||||
.job
|
||||
.info
|
||||
.caches
|
||||
.tts_model_record_cache
|
||||
.store_copy(&token, &model)
|
||||
.map_err(|err| ProcessSingleJobError::from_anyhow_error(err))?;
|
||||
MaybeInferenceModel::TtsModel(model)
|
||||
},
|
||||
|
||||
None => MaybeInferenceModel::None,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
(InferenceCategory::VoiceConversion, Some(token)) => {
|
||||
let maybe_model = job_dependencies.job.info.caches.vc_model_record_cache.copy_without_bump_if_unexpired(token.to_string())?;
|
||||
let maybe_model = job_dependencies
|
||||
.job
|
||||
.info
|
||||
.caches
|
||||
.vc_model_record_cache
|
||||
.copy_without_bump_if_unexpired(token.to_string())
|
||||
.map_err(|err| ProcessSingleJobError::from_anyhow_error(err))?;
|
||||
|
||||
match maybe_model {
|
||||
Some(model) => MaybeInferenceModel::VcModel(model),
|
||||
@@ -139,16 +160,22 @@ async fn get_model_record_from_cacheable_query(job_dependencies: &JobDependencie
|
||||
let maybe_vc_model = get_voice_conversion_model_for_inference(
|
||||
&job_dependencies.db.mysql_pool, token)
|
||||
.await
|
||||
.map_err(|err| anyhow!("database error: {:?}", err))?;
|
||||
.map_err(|err| ProcessSingleJobError::Other(anyhow!("database error: {:?}", err)))?;
|
||||
|
||||
match maybe_vc_model {
|
||||
None => MaybeInferenceModel::None,
|
||||
Some(model) => {
|
||||
let token = token.to_string();
|
||||
let _r = job_dependencies.job.info.caches.vc_model_record_cache.store_copy(&token, &model)?;
|
||||
let _r = job_dependencies
|
||||
.job
|
||||
.info
|
||||
.caches
|
||||
.vc_model_record_cache
|
||||
.store_copy(&token, &model)
|
||||
.map_err(|err| ProcessSingleJobError::from_anyhow_error(err))?;
|
||||
|
||||
MaybeInferenceModel::VcModel(model)
|
||||
},
|
||||
|
||||
None => MaybeInferenceModel::None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use std::time::Duration;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use log::{error, info, warn};
|
||||
|
||||
@@ -23,6 +23,9 @@ const INCREASE_TIMEOUT_MILLIS : u64 = 1000;
|
||||
/// Pause file millis
|
||||
const PAUSE_FILE_EXISTS_WAIT_MILLIS : u64 = 1000 * 30;
|
||||
|
||||
/// Warn on slow batch queries
|
||||
const SLOW_BATCH_QUERY_NOTICE_DURATION : Duration = Duration::from_millis(3500);
|
||||
|
||||
pub async fn main_loop(job_dependencies: JobDependencies) {
|
||||
let mut noop_logger = NoOpLogger::new(job_dependencies.job.system.no_op_logger_millis as i64);
|
||||
|
||||
@@ -46,6 +49,8 @@ pub async fn main_loop(job_dependencies: JobDependencies) {
|
||||
|
||||
let maybe_scoped_model_types = job_dependencies.job.system.scoped_execution.get_scoped_model_types();
|
||||
|
||||
let batch_query_start_time = Instant::now();
|
||||
|
||||
let maybe_available_jobs = list_available_generic_inference_jobs(ListAvailableGenericInferenceJobArgs {
|
||||
num_records: job_dependencies.job.system.job_batch_size,
|
||||
is_debug_worker: false, // TODO
|
||||
@@ -55,6 +60,12 @@ pub async fn main_loop(job_dependencies: JobDependencies) {
|
||||
mysql_pool: &job_dependencies.db.mysql_pool,
|
||||
}).await;
|
||||
|
||||
let batch_query_duration = Instant::now().duration_since(batch_query_start_time);
|
||||
|
||||
if batch_query_duration > SLOW_BATCH_QUERY_NOTICE_DURATION {
|
||||
warn!("Batch query took duration: {:?}", &batch_query_duration);
|
||||
}
|
||||
|
||||
sort_by_priority = true;
|
||||
sort_by_priority_count += 1;
|
||||
|
||||
@@ -106,11 +117,13 @@ pub async fn main_loop(job_dependencies: JobDependencies) {
|
||||
// This probably returns a struct or enum with some measure of how many GB need to be downloaded.
|
||||
|
||||
async fn process_job_batch(job_dependencies: &JobDependencies, jobs: Vec<AvailableInferenceJob>) -> AnyhowResult<()> {
|
||||
for job in jobs.into_iter() {
|
||||
let job_count = jobs.len();
|
||||
for (i, job) in jobs.into_iter().enumerate() {
|
||||
let result = process_single_job(job_dependencies, &job).await;
|
||||
|
||||
match result {
|
||||
Ok(success_case) => {
|
||||
info!("Job loop iteration \"success\": {:?}", success_case);
|
||||
info!("Job loop iteration ({i} of {job_count} batch) \"success\": {:?}", success_case);
|
||||
|
||||
let increment_success_count = match success_case {
|
||||
ProcessSingleJobSuccessCase::JobCompleted => true,
|
||||
@@ -125,7 +138,10 @@ async fn process_job_batch(job_dependencies: &JobDependencies, jobs: Vec<Availab
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
warn!("Failure to process job: {:?}", err);
|
||||
error!(
|
||||
r#"Failure to process job ({i} of {job_count} batch): {:?} -
|
||||
{:?}
|
||||
"#,job.inference_job_token, err);
|
||||
let _r = handle_error(&job_dependencies, &job, err).await?;
|
||||
}
|
||||
}
|
||||
@@ -191,7 +207,14 @@ async fn handle_error(job_dependencies: &&JobDependencies, job: &AvailableInfere
|
||||
None,
|
||||
Some(FrontendFailureCategory::FaceNotDetected),
|
||||
),
|
||||
|
||||
ProcessSingleJobError::ModelDeleted =>
|
||||
(
|
||||
JobFailureClass::PermanentFailure,
|
||||
ContainerHealth::Ignore,
|
||||
"model deleted".to_string(),
|
||||
None,
|
||||
None,
|
||||
),
|
||||
// Non-permanent failures
|
||||
ProcessSingleJobError::FilesystemFull =>
|
||||
(
|
||||
@@ -209,7 +232,14 @@ async fn handle_error(job_dependencies: &&JobDependencies, job: &AvailableInfere
|
||||
None, // Obviously don't tell the user about errors even we're not sure about
|
||||
Some(FrontendFailureCategory::RetryableWorkerError),
|
||||
),
|
||||
|
||||
ProcessSingleJobError::IoError(ref err) =>
|
||||
(
|
||||
JobFailureClass::TransientFailure,
|
||||
ContainerHealth::IncrementContainerFailCount,
|
||||
format!("IoError: {:?}", err),
|
||||
None, // Obviously don't tell the user about errors even we're not sure about
|
||||
Some(FrontendFailureCategory::RetryableWorkerError),
|
||||
),
|
||||
ProcessSingleJobError::JobSystemMisconfiguration(ref maybe_reason) =>
|
||||
(
|
||||
JobFailureClass::TransientFailure,
|
||||
@@ -261,6 +291,8 @@ async fn handle_error(job_dependencies: &&JobDependencies, job: &AvailableInfere
|
||||
ProcessSingleJobError::NotYetImplemented => {}
|
||||
ProcessSingleJobError::FaceDetectionFailure => {}
|
||||
ProcessSingleJobError::JobSystemMisconfiguration(_) => {}
|
||||
ProcessSingleJobError::ModelDeleted => {}
|
||||
ProcessSingleJobError::IoError(_) => {}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -11,7 +11,6 @@ use mysql_queries::queries::generic_inference::job::mark_generic_inference_job_s
|
||||
use redis_common::redis_keys::RedisKeys;
|
||||
|
||||
use crate::job::job_loop::determine_dependency_status::determine_dependency_status;
|
||||
use crate::job::job_loop::job_success_result::ResultEntity;
|
||||
use crate::job::job_loop::process_single_job_error::ProcessSingleJobError;
|
||||
use crate::job::job_loop::process_single_job_success_case::ProcessSingleJobSuccessCase;
|
||||
use crate::job::job_types::lipsync::process_single_lipsync_job::process_single_lipsync_job;
|
||||
@@ -40,15 +39,14 @@ pub async fn process_single_job(
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(bt,2023-07-23): Re-review the following. It looks sus.
|
||||
// TODO(bt,2023-07-23): Re-review the following. It looks sus.
|
||||
// TODO(bt,2023-07-23): Re-review the following. It looks sus.
|
||||
// TODO(bt,2023-07-23): Re-review the following. It looks sus.
|
||||
let dependency_status = determine_dependency_status(job_dependencies, job)
|
||||
.await
|
||||
.map_err(|err| ProcessSingleJobError::Other(anyhow!("database or cache error: {:?}", err)))?;
|
||||
.await?;
|
||||
|
||||
if !force_execution && !dependency_status.models_already_on_filesystem {
|
||||
if !force_execution
|
||||
&& !job_dependencies.job.system.always_allow_cold_filesystem_cache
|
||||
&& !dependency_status.models_already_on_filesystem
|
||||
{
|
||||
match dependency_status.maybe_model_token {
|
||||
None => {} // No model token, proceed
|
||||
Some(model_token) => {
|
||||
@@ -93,7 +91,7 @@ async fn process_single_job_wrap_with_logs(
|
||||
|
||||
println!("\n ----------------------------------------- JOB START ----------------------------------------- \n");
|
||||
|
||||
info!("Beginning work on job ({}): {:?}", job.id.0, job.inference_job_token);
|
||||
info!("Lock acquired. Beginning work on job ({}): {:?}", job.id.0, job.inference_job_token);
|
||||
info!("Job category: {:?}", job.inference_category);
|
||||
info!("Job model type: {:?}", job.maybe_model_type);
|
||||
info!("Job model token: {:?}", job.maybe_model_token);
|
||||
@@ -161,18 +159,19 @@ async fn do_process_single_job(
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== SETUP TEMP DIRS ==================== //
|
||||
|
||||
let temp_dir = format!("temp_{}", job.id.0);
|
||||
let temp_dir = job_dependencies.fs.scoped_temp_dir_creator_for_downloads.new_tempdir(&temp_dir)
|
||||
.map_err(|err| ProcessSingleJobError::Other(anyhow!("filesystem error: {:?}", err)))?;
|
||||
|
||||
let _p = temp_dir.path(); // TODO: Just so the build doesn't complain about unused. Remove.
|
||||
// NB(bt,2023-11-29): This looks dead, but hopefully isn't leaned on for downstream side effects.
|
||||
// I'll leave this commented out while dealing with the outage, but this can probably be removed
|
||||
// in a short while after we redeploy and verify all the jobs.
|
||||
// // ==================== SETUP TEMP DIRS ==================== //
|
||||
//
|
||||
// let temp_dir = format!("temp_{}", job.id.0);
|
||||
// let temp_dir = job_dependencies.fs.scoped_temp_dir_creator_for_short_lived_downloads.new_tempdir(&temp_dir)
|
||||
// .map_err(|err| ProcessSingleJobError::Other(anyhow!("filesystem error: {:?}", err)))?;
|
||||
//
|
||||
// let _p = temp_dir.path(); // TODO: Just so the build doesn't complain about unused. Remove.
|
||||
|
||||
// ==================== HANDLE DIFFERENT INFERENCE TYPES ==================== //
|
||||
|
||||
let mut maybe_result_entity : Option<ResultEntity>;
|
||||
|
||||
let job_success_result = match job.inference_category {
|
||||
InferenceCategory::LipsyncAnimation => {
|
||||
process_single_lipsync_job(job_dependencies, job).await?
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use anyhow::anyhow;
|
||||
use filesys::is_filesystem_full_error::is_filesystem_full_error;
|
||||
|
||||
/// Error from processing a single job
|
||||
#[derive(Debug)]
|
||||
@@ -25,6 +25,13 @@ pub enum ProcessSingleJobError {
|
||||
/// It might be important, we just haven't special cased it yet.
|
||||
Other(anyhow::Error),
|
||||
|
||||
/// This is a non-special-cased IO Error
|
||||
/// It might be important, we just haven't special cased it yet.
|
||||
IoError(std::io::Error),
|
||||
|
||||
/// Job underlying resources are missing - model deleted
|
||||
ModelDeleted,
|
||||
|
||||
/// The job system is misconfigured.
|
||||
/// Retry the job, but mark as a job runner system failure (health check failure).
|
||||
JobSystemMisconfiguration(Option<String>),
|
||||
@@ -34,25 +41,37 @@ pub enum ProcessSingleJobError {
|
||||
NotYetImplemented
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for ProcessSingleJobError {
|
||||
fn from(error: std::io::Error) -> Self {
|
||||
ProcessSingleJobError::from_io_error(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<anyhow::Error> for ProcessSingleJobError {
|
||||
fn from(error: anyhow::Error) -> Self {
|
||||
ProcessSingleJobError::from_anyhow_error(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl ProcessSingleJobError {
|
||||
pub fn from_io_error(error: std::io::Error) -> Self {
|
||||
match error.raw_os_error() {
|
||||
// NB: We can't use err.kind() -> ErrorKind::StorageFull, because it's marked unstable:
|
||||
// `io_error_more` is unstable [E0658]
|
||||
Some(28) => ProcessSingleJobError::FilesystemFull,
|
||||
_ => ProcessSingleJobError::Other(anyhow!(error)),
|
||||
if is_filesystem_full_error(&error) {
|
||||
ProcessSingleJobError::FilesystemFull
|
||||
} else {
|
||||
ProcessSingleJobError::IoError(error)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_anyhow_error(error: anyhow::Error) -> Self {
|
||||
match error.downcast_ref::<std::io::Error>() {
|
||||
Some(e) => match e.raw_os_error() {
|
||||
// NB: We can't use err.kind() -> ErrorKind::StorageFull, because it's marked unstable:
|
||||
// `io_error_more` is unstable [E0658]
|
||||
Some(28) => ProcessSingleJobError::FilesystemFull,
|
||||
_ => ProcessSingleJobError::Other(anyhow!(error)),
|
||||
match error.downcast::<std::io::Error>() {
|
||||
Ok(io_error) => {
|
||||
if is_filesystem_full_error(&io_error) {
|
||||
ProcessSingleJobError::FilesystemFull
|
||||
} else {
|
||||
ProcessSingleJobError::IoError(io_error)
|
||||
}
|
||||
},
|
||||
None => ProcessSingleJobError::Other(error),
|
||||
Err(anyhow_error) => ProcessSingleJobError::Other(anyhow_error),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -13,7 +13,9 @@ pub fn categorize_error(stderr_contents: &str) -> Option<ProcessSingleJobError>
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use anyhow::bail;
|
||||
use container_common::anyhow_result::AnyhowResult;
|
||||
|
||||
use errors::AnyhowResult;
|
||||
|
||||
use crate::job::job_loop::process_single_job_error::ProcessSingleJobError;
|
||||
use crate::job::job_types::lipsync::sad_talker::categorize_error::categorize_error;
|
||||
|
||||
|
||||
+11
-10
@@ -16,7 +16,7 @@ use mysql_queries::queries::voice_conversion::results::get_voice_conversion_resu
|
||||
use tokens::tokens::media_uploads::MediaUploadToken;
|
||||
|
||||
use crate::job::job_loop::process_single_job_error::ProcessSingleJobError;
|
||||
use crate::util::maybe_download_file_from_bucket::maybe_download_file_from_bucket;
|
||||
use crate::util::maybe_download_file_from_bucket::{maybe_download_file_from_bucket, MaybeDownloadArgs};
|
||||
use crate::util::scoped_temp_dir_creator::ScopedTempDirCreator;
|
||||
|
||||
pub struct AudioFile {
|
||||
@@ -94,16 +94,17 @@ pub async fn download_audio_file(
|
||||
|
||||
let downloaded_filesystem_path = work_temp_dir.path().join("audio.bin");
|
||||
|
||||
maybe_download_file_from_bucket(
|
||||
"audio file",
|
||||
&downloaded_filesystem_path,
|
||||
&bucket_object_path,
|
||||
public_bucket_client,
|
||||
maybe_download_file_from_bucket(MaybeDownloadArgs {
|
||||
name_or_description_of_file: "audio file",
|
||||
final_filesystem_file_path: &downloaded_filesystem_path,
|
||||
bucket_object_path: &bucket_object_path,
|
||||
bucket_client: public_bucket_client,
|
||||
job_progress_reporter,
|
||||
"downloading",
|
||||
job.id.0,
|
||||
&temp_dir_creator,
|
||||
).await?;
|
||||
job_progress_update_description: "downloading",
|
||||
job_id: job.id.0,
|
||||
scoped_tempdir_creator: &temp_dir_creator,
|
||||
maybe_existing_file_minimum_size_required: None,
|
||||
}).await?;
|
||||
|
||||
Ok(AudioFile {
|
||||
filesystem_path: downloaded_filesystem_path,
|
||||
|
||||
+11
-10
@@ -14,7 +14,7 @@ use mysql_queries::queries::media_uploads::get_media_upload_for_inference::get_m
|
||||
use tokens::tokens::media_uploads::MediaUploadToken;
|
||||
|
||||
use crate::job::job_loop::process_single_job_error::ProcessSingleJobError;
|
||||
use crate::util::maybe_download_file_from_bucket::maybe_download_file_from_bucket;
|
||||
use crate::util::maybe_download_file_from_bucket::{maybe_download_file_from_bucket, MaybeDownloadArgs};
|
||||
use crate::util::scoped_temp_dir_creator::ScopedTempDirCreator;
|
||||
|
||||
pub struct ImageFile {
|
||||
@@ -65,16 +65,17 @@ pub async fn download_image_file(
|
||||
|
||||
let downloaded_filesystem_path = work_temp_dir.path().join("image.bin");
|
||||
|
||||
maybe_download_file_from_bucket(
|
||||
"image file",
|
||||
&downloaded_filesystem_path,
|
||||
&bucket_object_path,
|
||||
public_bucket_client,
|
||||
maybe_download_file_from_bucket(MaybeDownloadArgs {
|
||||
name_or_description_of_file: "image file",
|
||||
final_filesystem_file_path: &downloaded_filesystem_path,
|
||||
bucket_object_path: &bucket_object_path,
|
||||
bucket_client: public_bucket_client,
|
||||
job_progress_reporter,
|
||||
"downloading",
|
||||
job.id.0,
|
||||
&temp_dir_creator,
|
||||
).await?;
|
||||
job_progress_update_description: "downloading",
|
||||
job_id: job.id.0,
|
||||
scoped_tempdir_creator: &temp_dir_creator,
|
||||
maybe_existing_file_minimum_size_required: None,
|
||||
}).await?;
|
||||
|
||||
Ok(ImageFile {
|
||||
filesystem_path: downloaded_filesystem_path,
|
||||
|
||||
+7
-7
@@ -5,11 +5,11 @@ use anyhow::anyhow;
|
||||
use log::{error, info, warn};
|
||||
|
||||
use buckets::public::media_files::original_file::MediaFileBucketPath;
|
||||
use container_common::filesystem::check_file_exists::check_file_exists;
|
||||
use container_common::filesystem::safe_delete_temp_directory::safe_delete_temp_directory;
|
||||
use container_common::filesystem::safe_delete_temp_file::safe_delete_temp_file;
|
||||
use enums::by_table::generic_inference_jobs::inference_result_type::InferenceResultType;
|
||||
use filesys::check_file_exists::check_file_exists;
|
||||
use filesys::file_size::file_size;
|
||||
use filesys::safe_delete_temp_directory::safe_delete_temp_directory;
|
||||
use filesys::safe_delete_temp_file::safe_delete_temp_file;
|
||||
use hashing::sha256::sha256_hash_file::sha256_hash_file;
|
||||
use mimetypes::mimetype_for_file::get_mimetype_for_file;
|
||||
use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob;
|
||||
@@ -74,12 +74,12 @@ pub async fn process_job(args: SadTalkerProcessJobArgs<'_>) -> Result<JobSuccess
|
||||
|
||||
let result = downloader.download_if_not_on_filesystem(
|
||||
&args.job_dependencies.buckets.private_bucket_client,
|
||||
&args.job_dependencies.fs.scoped_temp_dir_creator_for_downloads,
|
||||
&args.job_dependencies.fs.scoped_temp_dir_creator_for_short_lived_downloads,
|
||||
).await;
|
||||
|
||||
if let Err(e) = result {
|
||||
error!("could not download: {:?}", e);
|
||||
return Err(ProcessSingleJobError::from_anyhow_error(e))
|
||||
if let Err(err) = result {
|
||||
error!("could not download: {:?}", err);
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ use log::info;
|
||||
use once_cell::sync::Lazy;
|
||||
use subprocess::{Popen, PopenConfig, Redirection};
|
||||
|
||||
use container_common::anyhow_result::AnyhowResult;
|
||||
use errors::AnyhowResult;
|
||||
use filesys::path_to_string::path_to_string;
|
||||
use subprocess_common::docker_options::{DockerFilesystemMount, DockerGpu, DockerOptions};
|
||||
|
||||
|
||||
+34
-32
@@ -6,7 +6,7 @@ use mysql_queries::queries::generic_inference::job::list_available_generic_infer
|
||||
use crate::job::job_loop::process_single_job_error::ProcessSingleJobError;
|
||||
use crate::job::job_types::tts::tacotron2_v2_early_fakeyou::tacotron2_dependencies::Tacotron2Dependencies;
|
||||
use crate::job_dependencies::JobDependencies;
|
||||
use crate::util::maybe_download_file_from_bucket::maybe_download_file_from_bucket;
|
||||
use crate::util::maybe_download_file_from_bucket::{maybe_download_file_from_bucket, MaybeDownloadArgs};
|
||||
|
||||
pub struct StaticDependencies {
|
||||
pub waveglow_vocoder_model_fs_path : PathBuf,
|
||||
@@ -22,7 +22,6 @@ pub async fn download_static_dependencies<'a>(
|
||||
mut job_progress_reporter: &mut Box<dyn JobProgressReporter>,
|
||||
) -> Result<StaticDependencies, ProcessSingleJobError> {
|
||||
|
||||
|
||||
// ==================== CONFIRM OR DOWNLOAD WAVEGLOW VOCODER MODEL ==================== //
|
||||
|
||||
let waveglow_vocoder_model_fs_path = {
|
||||
@@ -31,16 +30,17 @@ pub async fn download_static_dependencies<'a>(
|
||||
let waveglow_vocoder_model_fs_path = job_dependencies.fs.semi_persistent_cache.tts_pretrained_vocoder_model_path(&waveglow_vocoder_model_filename);
|
||||
let waveglow_vocoder_model_object_path = job_dependencies.buckets.bucket_path_unifier.tts_pretrained_vocoders_path(&waveglow_vocoder_model_filename);
|
||||
|
||||
maybe_download_file_from_bucket(
|
||||
"waveglow vocoder model",
|
||||
&waveglow_vocoder_model_fs_path,
|
||||
&waveglow_vocoder_model_object_path,
|
||||
&job_dependencies.buckets.private_bucket_client,
|
||||
&mut job_progress_reporter,
|
||||
"downloading vocoder (1 of 3)",
|
||||
job.id.0,
|
||||
&job_dependencies.fs.scoped_temp_dir_creator_for_downloads,
|
||||
).await?;
|
||||
maybe_download_file_from_bucket(MaybeDownloadArgs {
|
||||
name_or_description_of_file: "waveglow vocoder model",
|
||||
final_filesystem_file_path: &waveglow_vocoder_model_fs_path,
|
||||
bucket_object_path: &waveglow_vocoder_model_object_path,
|
||||
bucket_client: &job_dependencies.buckets.private_bucket_client,
|
||||
job_progress_reporter: &mut job_progress_reporter,
|
||||
job_progress_update_description: "downloading vocoder (1 of 3)",
|
||||
job_id: job.id.0,
|
||||
scoped_tempdir_creator: &job_dependencies.fs.scoped_temp_dir_creator_for_long_lived_downloads,
|
||||
maybe_existing_file_minimum_size_required: Some(1000),
|
||||
}).await?;
|
||||
|
||||
waveglow_vocoder_model_fs_path
|
||||
};
|
||||
@@ -53,16 +53,17 @@ pub async fn download_static_dependencies<'a>(
|
||||
let hifigan_vocoder_model_fs_path = job_dependencies.fs.semi_persistent_cache.tts_pretrained_vocoder_model_path(&hifigan_vocoder_model_filename);
|
||||
let hifigan_vocoder_model_object_path = job_dependencies.buckets.bucket_path_unifier.tts_pretrained_vocoders_path(&hifigan_vocoder_model_filename);
|
||||
|
||||
maybe_download_file_from_bucket(
|
||||
"hifigan vocoder model",
|
||||
&hifigan_vocoder_model_fs_path,
|
||||
&hifigan_vocoder_model_object_path,
|
||||
&job_dependencies.buckets.private_bucket_client,
|
||||
&mut job_progress_reporter,
|
||||
"downloading vocoder (2 of 3)",
|
||||
job.id.0,
|
||||
&job_dependencies.fs.scoped_temp_dir_creator_for_downloads,
|
||||
).await?;
|
||||
maybe_download_file_from_bucket(MaybeDownloadArgs {
|
||||
name_or_description_of_file: "hifigan vocoder model",
|
||||
final_filesystem_file_path: &hifigan_vocoder_model_fs_path,
|
||||
bucket_object_path: &hifigan_vocoder_model_object_path,
|
||||
bucket_client: &job_dependencies.buckets.private_bucket_client,
|
||||
job_progress_reporter: &mut job_progress_reporter,
|
||||
job_progress_update_description: "downloading vocoder (2 of 3)",
|
||||
job_id: job.id.0,
|
||||
scoped_tempdir_creator: &job_dependencies.fs.scoped_temp_dir_creator_for_long_lived_downloads,
|
||||
maybe_existing_file_minimum_size_required: Some(1000),
|
||||
}).await?;
|
||||
|
||||
hifigan_vocoder_model_fs_path
|
||||
};
|
||||
@@ -75,16 +76,17 @@ pub async fn download_static_dependencies<'a>(
|
||||
let hifigan_superres_vocoder_model_fs_path = job_dependencies.fs.semi_persistent_cache.tts_pretrained_vocoder_model_path(&hifigan_superres_vocoder_model_filename);
|
||||
let hifigan_superres_vocoder_model_object_path = job_dependencies.buckets.bucket_path_unifier.tts_pretrained_vocoders_path(&hifigan_superres_vocoder_model_filename);
|
||||
|
||||
maybe_download_file_from_bucket(
|
||||
"hifigan superres vocoder model",
|
||||
&hifigan_superres_vocoder_model_fs_path,
|
||||
&hifigan_superres_vocoder_model_object_path,
|
||||
&job_dependencies.buckets.private_bucket_client,
|
||||
&mut job_progress_reporter,
|
||||
"downloading vocoder (3 of 3)",
|
||||
job.id.0,
|
||||
&job_dependencies.fs.scoped_temp_dir_creator_for_downloads,
|
||||
).await?;
|
||||
maybe_download_file_from_bucket(MaybeDownloadArgs {
|
||||
name_or_description_of_file: "hifigan superres vocoder model",
|
||||
final_filesystem_file_path: &hifigan_superres_vocoder_model_fs_path,
|
||||
bucket_object_path: &hifigan_superres_vocoder_model_object_path,
|
||||
bucket_client: &job_dependencies.buckets.private_bucket_client,
|
||||
job_progress_reporter: &mut job_progress_reporter,
|
||||
job_progress_update_description: "downloading vocoder (3 of 3)",
|
||||
job_id: job.id.0,
|
||||
scoped_tempdir_creator: &job_dependencies.fs.scoped_temp_dir_creator_for_long_lived_downloads,
|
||||
maybe_existing_file_minimum_size_required: Some(1000),
|
||||
}).await?;
|
||||
|
||||
hifigan_superres_vocoder_model_fs_path
|
||||
};
|
||||
|
||||
+1
@@ -8,4 +8,5 @@ pub mod tacotron2_dependencies;
|
||||
pub mod tacotron2_inference_command;
|
||||
pub mod tacotron2_inference_sidecar_client;
|
||||
pub mod tacotron2_sidecar_health_check_client;
|
||||
pub mod virtual_lfu_cache;
|
||||
pub mod vocoder_option;
|
||||
|
||||
+44
-27
@@ -7,11 +7,11 @@ use anyhow::anyhow;
|
||||
use log::{error, info};
|
||||
use tempdir::TempDir;
|
||||
|
||||
use container_common::filesystem::check_file_exists::check_file_exists;
|
||||
use container_common::filesystem::safe_delete_temp_directory::safe_delete_temp_directory;
|
||||
use container_common::filesystem::safe_delete_temp_file::safe_delete_temp_file;
|
||||
use enums::by_table::generic_inference_jobs::inference_result_type::InferenceResultType;
|
||||
use errors::AnyhowResult;
|
||||
use filesys::check_file_exists::check_file_exists;
|
||||
use filesys::safe_delete_temp_directory::safe_delete_temp_directory;
|
||||
use filesys::safe_delete_temp_file::safe_delete_temp_file;
|
||||
use hashing::sha256::sha256_hash_string::sha256_hash_string;
|
||||
use mysql_queries::column_types::vocoder_type::VocoderType;
|
||||
use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob;
|
||||
@@ -29,7 +29,7 @@ use crate::job::job_types::tts::tacotron2_v2_early_fakeyou::seconds_to_decoder_s
|
||||
use crate::job::job_types::tts::tacotron2_v2_early_fakeyou::tacotron2_inference_command::{InferenceArgs, MelMultiplyFactor};
|
||||
use crate::job::job_types::tts::tacotron2_v2_early_fakeyou::vocoder_option::VocoderForInferenceOption;
|
||||
use crate::job_dependencies::JobDependencies;
|
||||
use crate::util::maybe_download_file_from_bucket::maybe_download_file_from_bucket;
|
||||
use crate::util::maybe_download_file_from_bucket::{maybe_download_file_from_bucket, MaybeDownloadArgs};
|
||||
|
||||
/// Text starting with this will be treated as a test request.
|
||||
/// This allows the request to bypass the model cache and query the latest TTS model.
|
||||
@@ -58,7 +58,7 @@ pub async fn process_job(args: ProcessJobArgs<'_>) -> Result<JobSuccessResult, P
|
||||
|
||||
// NB: The first time TT2 on inference-job was deployed, the filesystem filled up with
|
||||
// temporary directories. This is just being abundantly safe.
|
||||
info!("Deleting temp directory: {:?}", work_temp_dir.path());
|
||||
info!("(After job cleanup) Deleting temp directory: {:?}", work_temp_dir.path());
|
||||
safe_delete_temp_directory(&work_temp_dir);
|
||||
|
||||
result
|
||||
@@ -119,16 +119,17 @@ async fn process_job_with_cleanup(
|
||||
let custom_vocoder_fs_path = args.job_dependencies.fs.semi_persistent_cache.custom_vocoder_model_path(&vocoder.vocoder_token);
|
||||
let custom_vocoder_object_path = args.job_dependencies.buckets.bucket_path_unifier.vocoder_path(&vocoder.vocoder_private_bucket_hash);
|
||||
|
||||
maybe_download_file_from_bucket(
|
||||
"custom vocoder",
|
||||
&custom_vocoder_fs_path,
|
||||
&custom_vocoder_object_path,
|
||||
&args.job_dependencies.buckets.private_bucket_client,
|
||||
&mut job_progress_reporter,
|
||||
"downloading user vocoder",
|
||||
job.id.0,
|
||||
&args.job_dependencies.fs.scoped_temp_dir_creator_for_downloads,
|
||||
).await?;
|
||||
maybe_download_file_from_bucket(MaybeDownloadArgs {
|
||||
name_or_description_of_file: "custom vocoder",
|
||||
final_filesystem_file_path: &custom_vocoder_fs_path,
|
||||
bucket_object_path: &custom_vocoder_object_path,
|
||||
bucket_client: &args.job_dependencies.buckets.private_bucket_client,
|
||||
job_progress_reporter: &mut job_progress_reporter,
|
||||
job_progress_update_description: "downloading user vocoder",
|
||||
job_id: job.id.0,
|
||||
scoped_tempdir_creator: &args.job_dependencies.fs.scoped_temp_dir_creator_for_short_lived_downloads,
|
||||
maybe_existing_file_minimum_size_required: Some(1000),
|
||||
}).await?;
|
||||
|
||||
Some(custom_vocoder_fs_path)
|
||||
}
|
||||
@@ -140,16 +141,17 @@ async fn process_job_with_cleanup(
|
||||
let tts_synthesizer_fs_path = args.job_dependencies.fs.semi_persistent_cache.tts_synthesizer_model_path(tts_model.model_token.as_str());
|
||||
let tts_synthesizer_object_path = args.job_dependencies.buckets.bucket_path_unifier.tts_synthesizer_path(&tts_model.private_bucket_hash);
|
||||
|
||||
maybe_download_file_from_bucket(
|
||||
"synthesizer",
|
||||
&tts_synthesizer_fs_path,
|
||||
&tts_synthesizer_object_path,
|
||||
&args.job_dependencies.buckets.private_bucket_client,
|
||||
&mut job_progress_reporter,
|
||||
"downloading synthesizer",
|
||||
job.id.0,
|
||||
&args.job_dependencies.fs.scoped_temp_dir_creator_for_downloads,
|
||||
).await?;
|
||||
maybe_download_file_from_bucket(MaybeDownloadArgs {
|
||||
name_or_description_of_file: "synthesizer",
|
||||
final_filesystem_file_path: & tts_synthesizer_fs_path,
|
||||
bucket_object_path: &tts_synthesizer_object_path,
|
||||
bucket_client: &args.job_dependencies.buckets.private_bucket_client,
|
||||
job_progress_reporter: &mut job_progress_reporter,
|
||||
job_progress_update_description: "downloading synthesizer",
|
||||
job_id: job.id.0,
|
||||
scoped_tempdir_creator: &args.job_dependencies.fs.scoped_temp_dir_creator_for_short_lived_downloads,
|
||||
maybe_existing_file_minimum_size_required: Some(1000),
|
||||
}).await?;
|
||||
|
||||
tts_synthesizer_fs_path
|
||||
};
|
||||
@@ -238,12 +240,20 @@ async fn process_job_with_cleanup(
|
||||
maybe_mel_multiply_factor = Some(MelMultiplyFactor::DefaultMultiplyFactor);
|
||||
}
|
||||
|
||||
// TODO(bt,2023-11-27): Handle LRU cache on python side
|
||||
let maybe_unload_model_path = None;
|
||||
let maybe_unload_model_path = model_dependencies
|
||||
.sidecar
|
||||
.virtual_lfu_cache
|
||||
.insert_returning_replaced(tts_synthesizer_fs_path.to_str().unwrap_or(""))
|
||||
.map_err(|e| ProcessSingleJobError::Other(e))?;
|
||||
|
||||
if let Some(model_path) = maybe_unload_model_path.as_deref() {
|
||||
info!("Remove model from sidecar LFU cache: {:?}", model_path);
|
||||
}
|
||||
|
||||
let inference_start_time = Instant::now();
|
||||
|
||||
if model_dependencies.sidecar.use_sidecar_instead_of_shell {
|
||||
info!("Calling inference sidecar...");
|
||||
let _r = model_dependencies.sidecar.inference_client.request_inference(
|
||||
&cleaned_inference_text,
|
||||
max_decoder_steps,
|
||||
@@ -258,6 +268,7 @@ async fn process_job_with_cleanup(
|
||||
tts_model.maybe_custom_mel_multiply_factor,
|
||||
).await.map_err(|e| ProcessSingleJobError::Other(e))?;
|
||||
} else {
|
||||
info!("Shelling out for inference...");
|
||||
let _r = model_dependencies.inference_command.execute_inference(InferenceArgs {
|
||||
synthesizer_checkpoint_path: &tts_synthesizer_fs_path,
|
||||
text_pipeline_type: text_pipeline_type_or_guess.to_str(),
|
||||
@@ -283,9 +294,15 @@ async fn process_job_with_cleanup(
|
||||
check_file_exists(&output_spectrogram_fs_path).map_err(|e| ProcessSingleJobError::Other(e))?;
|
||||
check_file_exists(&output_metadata_fs_path).map_err(|e| ProcessSingleJobError::Other(e))?;
|
||||
|
||||
info!("All required files exist!");
|
||||
|
||||
info!("Reading metadata file...");
|
||||
|
||||
let file_metadata = read_metadata_file(&output_metadata_fs_path)
|
||||
.map_err(|e| ProcessSingleJobError::Other(e))?;
|
||||
|
||||
info!("Deleting metadata file...");
|
||||
|
||||
safe_delete_temp_file(&output_metadata_fs_path);
|
||||
|
||||
// ==================== UPLOAD AUDIO TO BUCKET ==================== //
|
||||
|
||||
+9
-1
@@ -1,9 +1,10 @@
|
||||
use errors::AnyhowResult;
|
||||
use crate::job::job_types::tts::tacotron2_v2_early_fakeyou::health_check_state::HealthCheckState;
|
||||
|
||||
use crate::job::job_types::tts::tacotron2_v2_early_fakeyou::health_check_state::HealthCheckState;
|
||||
use crate::job::job_types::tts::tacotron2_v2_early_fakeyou::tacotron2_inference_command::Tacotron2InferenceCommand;
|
||||
use crate::job::job_types::tts::tacotron2_v2_early_fakeyou::tacotron2_inference_sidecar_client::Tacotron2InferenceSidecarClient;
|
||||
use crate::job::job_types::tts::tacotron2_v2_early_fakeyou::tacotron2_sidecar_health_check_client::Tacotron2SidecarHealthCheckClient;
|
||||
use crate::job::job_types::tts::tacotron2_v2_early_fakeyou::virtual_lfu_cache::SyncVirtualLfuCache;
|
||||
|
||||
pub struct Tacotron2Dependencies {
|
||||
pub inference_command: Tacotron2InferenceCommand,
|
||||
@@ -26,6 +27,7 @@ pub struct SidecarDeps {
|
||||
pub inference_client: Tacotron2InferenceSidecarClient,
|
||||
pub health_check_client: Tacotron2SidecarHealthCheckClient,
|
||||
pub health_check_state: HealthCheckState,
|
||||
pub virtual_lfu_cache: SyncVirtualLfuCache,
|
||||
}
|
||||
|
||||
impl Tacotron2Dependencies {
|
||||
@@ -53,6 +55,11 @@ impl Tacotron2Dependencies {
|
||||
let health_check_client=
|
||||
Tacotron2SidecarHealthCheckClient::new(&sidecar_hostname)?;
|
||||
|
||||
let sidecar_max_synthesizer_models = easyenv::get_env_num(
|
||||
"TTS_SIDECAR_MAX_SYNTHESIZER_MODELS", 3)?;
|
||||
|
||||
let virtual_lfu_cache = SyncVirtualLfuCache::new(sidecar_max_synthesizer_models)?;
|
||||
|
||||
Ok(Self {
|
||||
inference_command: Tacotron2InferenceCommand::from_env()?,
|
||||
waveglow_vocoder_model_filename,
|
||||
@@ -63,6 +70,7 @@ impl Tacotron2Dependencies {
|
||||
inference_client,
|
||||
health_check_client,
|
||||
health_check_state: HealthCheckState::new(),
|
||||
virtual_lfu_cache,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
+11
-2
@@ -5,7 +5,7 @@ use hyper::{Body, Request};
|
||||
use hyper::client::Client;
|
||||
use log::info;
|
||||
|
||||
use container_common::anyhow_result::AnyhowResult;
|
||||
use errors::AnyhowResult;
|
||||
use filesys::path_to_string::path_to_string;
|
||||
use mysql_queries::column_types::vocoder_type::VocoderType;
|
||||
|
||||
@@ -160,7 +160,16 @@ impl Tacotron2InferenceSidecarClient {
|
||||
|
||||
let client = Client::new();
|
||||
|
||||
let _maybe_response = client.request(req).await?;
|
||||
let response = client.request(req).await?;
|
||||
let status = response.status();
|
||||
|
||||
info!("Response status: {} ({:?})", status, status.canonical_reason());
|
||||
|
||||
if status.is_server_error() {
|
||||
return Err(anyhow!("sidecar server error: {} {:?}", status, status.canonical_reason()));
|
||||
} else if status.is_client_error() {
|
||||
return Err(anyhow!("sidecar client request error: {} {:?}", status, status.canonical_reason()));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ use hyper::client::Client;
|
||||
use hyper::Uri;
|
||||
use log::info;
|
||||
|
||||
use container_common::anyhow_result::AnyhowResult;
|
||||
use errors::AnyhowResult;
|
||||
|
||||
// TODO(bt): As more microservices adopt a common health check protocol,
|
||||
// it may make sense to make this a common library.
|
||||
|
||||
+206
@@ -0,0 +1,206 @@
|
||||
use std::collections::HashSet;
|
||||
use std::sync::{Arc, RwLock};
|
||||
|
||||
use anyhow::anyhow;
|
||||
use lfu::LFUCache;
|
||||
|
||||
use errors::AnyhowResult;
|
||||
|
||||
/// This stands in front of the python HTTP sidecar and controls which
|
||||
/// models get to remain in memory. The Python sidecar keeps multiple
|
||||
/// models around, and Rust dictates which ones to keep and which to
|
||||
/// purge.
|
||||
pub struct VirtualLfuCache {
|
||||
cache: LFUCache<String, ()>,
|
||||
}
|
||||
|
||||
/// And the Sync/Send threadsafe + interior mutability version.
|
||||
#[derive(Clone)]
|
||||
pub struct SyncVirtualLfuCache {
|
||||
cache: Arc::<RwLock<VirtualLfuCache>>
|
||||
}
|
||||
|
||||
impl VirtualLfuCache {
|
||||
|
||||
pub fn new(capacity: usize) -> AnyhowResult<Self> {
|
||||
let cache = LFUCache::with_capacity(capacity)
|
||||
.map_err(|e| anyhow!("Error creating cache (probably capacity): {:?}", e))?;
|
||||
Ok(Self {
|
||||
cache,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn in_cache(&self, model: &String) -> bool {
|
||||
self.cache.contains(model)
|
||||
}
|
||||
|
||||
/// Returns the evicted entry.
|
||||
pub fn insert_returning_replaced(&mut self, path: &str) -> Option<String> {
|
||||
let initial_keys = self.get_keyset();
|
||||
|
||||
self.cache.set(path.to_string(), ());
|
||||
|
||||
let after_keys = self.get_keyset();
|
||||
|
||||
let difference = initial_keys.difference(&after_keys);
|
||||
|
||||
difference.last()
|
||||
.map(|item| item.to_string())
|
||||
}
|
||||
|
||||
pub fn size(&self) -> usize {
|
||||
self.cache.len()
|
||||
}
|
||||
|
||||
fn get_keyset(&self) -> HashSet<String> {
|
||||
// NB: This only makes sense for our use while we're using small caches.
|
||||
let mut key_set = HashSet::with_capacity(self.size());
|
||||
for (k, _) in self.cache.iter() {
|
||||
key_set.insert(k.to_string());
|
||||
}
|
||||
key_set
|
||||
}
|
||||
}
|
||||
|
||||
impl SyncVirtualLfuCache {
|
||||
|
||||
pub fn new(capacity: usize) -> AnyhowResult<Self> {
|
||||
let cache = VirtualLfuCache::new(capacity)?;
|
||||
Ok(Self {
|
||||
cache: Arc::new(RwLock::new(cache)),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn in_cache(&self, model: &String) -> AnyhowResult<bool> {
|
||||
let exists = self.cache
|
||||
.read()
|
||||
.map(|cache| cache.in_cache(model))
|
||||
.map_err(|err| anyhow!("mutex error: {:?}", err))?;
|
||||
Ok(exists)
|
||||
}
|
||||
|
||||
/// Returns the evicted entry.
|
||||
pub fn insert_returning_replaced(&self, path: &str) -> AnyhowResult<Option<String>> {
|
||||
let maybe_replaced = self.cache
|
||||
.write()
|
||||
.map(|mut cache| cache.insert_returning_replaced(path))
|
||||
.map_err(|err| anyhow!("mutex error: {:?}", err))?;
|
||||
Ok(maybe_replaced)
|
||||
}
|
||||
|
||||
pub fn size(&self) -> AnyhowResult<usize> {
|
||||
let size = self.cache
|
||||
.read()
|
||||
.map(|cache| cache.size())
|
||||
.map_err(|err| anyhow!("mutex error: {:?}", err))?;
|
||||
Ok(size)
|
||||
}
|
||||
|
||||
fn get_keyset(&self) -> AnyhowResult<HashSet<String>> {
|
||||
let key_set = self.cache
|
||||
.read()
|
||||
.map(|cache| cache.get_keyset())
|
||||
.map_err(|err| anyhow!("mutex error: {:?}", err))?;
|
||||
Ok(key_set)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use crate::job::job_types::tts::tacotron2_v2_early_fakeyou::virtual_lfu_cache::VirtualLfuCache;
|
||||
|
||||
#[test]
|
||||
fn large_capacity_does_not_shed() {
|
||||
let mut cache = VirtualLfuCache::new(10).unwrap();
|
||||
cache.insert_returning_replaced("1");
|
||||
cache.insert_returning_replaced("2");
|
||||
cache.insert_returning_replaced("3");
|
||||
cache.insert_returning_replaced("4");
|
||||
cache.insert_returning_replaced("5");
|
||||
cache.insert_returning_replaced("6");
|
||||
cache.insert_returning_replaced("7");
|
||||
cache.insert_returning_replaced("8");
|
||||
cache.insert_returning_replaced("9");
|
||||
assert!(cache.insert_returning_replaced("10").is_none()); // Does not remove
|
||||
assert!(cache.insert_returning_replaced("11").is_some()); // Removes
|
||||
assert_eq!(cache.size(), 10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_beyond_capacity() {
|
||||
let mut cache = VirtualLfuCache::new(3).unwrap();
|
||||
assert_eq!(cache.size(), 0);
|
||||
cache.insert_returning_replaced("foo");
|
||||
assert_eq!(cache.size(), 1);
|
||||
cache.insert_returning_replaced("bar");
|
||||
assert_eq!(cache.size(), 2);
|
||||
cache.insert_returning_replaced("baz");
|
||||
assert_eq!(cache.size(), 3);
|
||||
cache.insert_returning_replaced("bin");
|
||||
assert_eq!(cache.size(), 3);
|
||||
cache.insert_returning_replaced("bin");
|
||||
assert_eq!(cache.size(), 3);
|
||||
cache.insert_returning_replaced("111111111111111111");
|
||||
assert_eq!(cache.size(), 3);
|
||||
}
|
||||
|
||||
fn repeated_insert_single_key() {
|
||||
let mut cache = VirtualLfuCache::new(3).unwrap();
|
||||
assert_eq!(cache.size(), 0);
|
||||
for _ in 0..10 {
|
||||
cache.insert_returning_replaced("foo");
|
||||
}
|
||||
assert_eq!(cache.size(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn returns_first_for_eviction_when_all_used_once() {
|
||||
let mut cache = VirtualLfuCache::new(3).unwrap();
|
||||
cache.insert_returning_replaced("foo");
|
||||
cache.insert_returning_replaced("bar");
|
||||
cache.insert_returning_replaced("baz");
|
||||
let discarded = cache.insert_returning_replaced("bin");
|
||||
assert_eq!(discarded, Some("foo".to_string()));
|
||||
|
||||
assert_eq!(false, cache.in_cache(&"foo".to_string()));
|
||||
assert_eq!(true, cache.in_cache(&"bar".to_string()));
|
||||
assert_eq!(true, cache.in_cache(&"baz".to_string()));
|
||||
assert_eq!(true, cache.in_cache(&"bin".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn retains_frequent_value() {
|
||||
let mut cache = VirtualLfuCache::new(3).unwrap();
|
||||
for _ in 0..10 {
|
||||
cache.insert_returning_replaced("foo");
|
||||
}
|
||||
cache.insert_returning_replaced("bar");
|
||||
cache.insert_returning_replaced("baz");
|
||||
let discarded = cache.insert_returning_replaced("bin");
|
||||
assert_eq!(discarded, Some("bar".to_string()));
|
||||
|
||||
assert_eq!(true, cache.in_cache(&"foo".to_string()));
|
||||
assert_eq!(false, cache.in_cache(&"bar".to_string()));
|
||||
assert_eq!(true, cache.in_cache(&"baz".to_string()));
|
||||
assert_eq!(true, cache.in_cache(&"bin".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn retains_second_frequent_value() {
|
||||
let mut cache = VirtualLfuCache::new(3).unwrap();
|
||||
for _ in 0..10 {
|
||||
cache.insert_returning_replaced("foo");
|
||||
}
|
||||
for _ in 0..2 {
|
||||
cache.insert_returning_replaced("bar");
|
||||
}
|
||||
cache.insert_returning_replaced("baz");
|
||||
let discarded = cache.insert_returning_replaced("bin");
|
||||
assert_eq!(discarded, Some("baz".to_string()));
|
||||
|
||||
assert_eq!(true, cache.in_cache(&"foo".to_string()));
|
||||
assert_eq!(true, cache.in_cache(&"bar".to_string()));
|
||||
assert_eq!(false, cache.in_cache(&"baz".to_string()));
|
||||
assert_eq!(true, cache.in_cache(&"bin".to_string()));
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -177,11 +177,11 @@ pub async fn process_create_voice(
|
||||
for downloader in model_dependencies.downloaders.all_downloaders() {
|
||||
let result = downloader.download_if_not_on_filesystem(
|
||||
&args.job_dependencies.buckets.private_bucket_client,
|
||||
&args.job_dependencies.fs.scoped_temp_dir_creator_for_downloads
|
||||
&args.job_dependencies.fs.scoped_temp_dir_creator_for_short_lived_downloads
|
||||
).await;
|
||||
if let Err(e) = result {
|
||||
error!("could not download: {:?}", e);
|
||||
return Err(ProcessSingleJobError::from_anyhow_error(e));
|
||||
if let Err(err) = result {
|
||||
error!("could not download: {:?}", err);
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -82,12 +82,12 @@ pub async fn process_inference_voice(
|
||||
for downloader in model_dependencies.downloaders.all_downloaders() {
|
||||
let result = downloader.download_if_not_on_filesystem(
|
||||
&args.job_dependencies.buckets.private_bucket_client,
|
||||
&args.job_dependencies.fs.scoped_temp_dir_creator_for_downloads
|
||||
&args.job_dependencies.fs.scoped_temp_dir_creator_for_short_lived_downloads
|
||||
).await;
|
||||
|
||||
if let Err(e) = result {
|
||||
error!("could not download: {:?}", e);
|
||||
return Err(ProcessSingleJobError::from_anyhow_error(e));
|
||||
if let Err(err) = result {
|
||||
error!("could not download: {:?}", err);
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -2,17 +2,17 @@ use std::collections::HashSet;
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::fs::File;
|
||||
use std::path::{ Path, PathBuf };
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::anyhow;
|
||||
use log::info;
|
||||
use once_cell::sync::Lazy;
|
||||
use subprocess::{ Popen, PopenConfig, Redirection };
|
||||
use subprocess::{Popen, PopenConfig, Redirection};
|
||||
|
||||
use container_common::anyhow_result::AnyhowResult;
|
||||
use errors::AnyhowResult;
|
||||
use filesys::path_to_string::path_to_string;
|
||||
use subprocess_common::docker_options::{ DockerFilesystemMount, DockerGpu, DockerOptions };
|
||||
use subprocess_common::docker_options::{DockerFilesystemMount, DockerGpu, DockerOptions};
|
||||
|
||||
use crate::job::job_loop::command_exit_status::CommandExitStatus;
|
||||
|
||||
|
||||
@@ -7,11 +7,11 @@ use anyhow::anyhow;
|
||||
use log::{error, info};
|
||||
use tempdir::TempDir;
|
||||
|
||||
use container_common::filesystem::check_file_exists::check_file_exists;
|
||||
use container_common::filesystem::safe_delete_temp_directory::safe_delete_temp_directory;
|
||||
use container_common::filesystem::safe_delete_temp_file::safe_delete_temp_file;
|
||||
use enums::by_table::generic_inference_jobs::inference_result_type::InferenceResultType;
|
||||
use errors::AnyhowResult;
|
||||
use filesys::check_file_exists::check_file_exists;
|
||||
use filesys::safe_delete_temp_directory::safe_delete_temp_directory;
|
||||
use filesys::safe_delete_temp_file::safe_delete_temp_file;
|
||||
use hashing::sha256::sha256_hash_string::sha256_hash_string;
|
||||
use mysql_queries::column_types::vocoder_type::VocoderType;
|
||||
use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob;
|
||||
@@ -22,7 +22,7 @@ use crate::job::job_loop::job_success_result::{JobSuccessResult, ResultEntity};
|
||||
use crate::job::job_loop::process_single_job_error::ProcessSingleJobError;
|
||||
use crate::job::job_types::tts::vits::vits_inference_command::{Device, VitsInferenceArgs};
|
||||
use crate::job_dependencies::JobDependencies;
|
||||
use crate::util::maybe_download_file_from_bucket::maybe_download_file_from_bucket;
|
||||
use crate::util::maybe_download_file_from_bucket::{maybe_download_file_from_bucket, MaybeDownloadArgs};
|
||||
|
||||
/// Text starting with this will be treated as a test request.
|
||||
/// This allows the request to bypass the model cache and query the latest TTS model.
|
||||
@@ -70,16 +70,17 @@ pub async fn process_job(args: VitsProcessJobArgs<'_>) -> Result<JobSuccessResul
|
||||
// In the future we may need to "repair" broken models.
|
||||
let vits_traced_synthesizer_object_path = args.job_dependencies.buckets.bucket_path_unifier.tts_traced_synthesizer_path(&tts_model.private_bucket_hash);
|
||||
|
||||
maybe_download_file_from_bucket(
|
||||
"vits traced tts model",
|
||||
&vits_traced_synthesizer_fs_path,
|
||||
&vits_traced_synthesizer_object_path,
|
||||
&args.job_dependencies.buckets.private_bucket_client,
|
||||
&mut job_progress_reporter,
|
||||
"downloading synthesizer",
|
||||
job.id.0,
|
||||
&args.job_dependencies.fs.scoped_temp_dir_creator_for_downloads,
|
||||
).await?;
|
||||
maybe_download_file_from_bucket(MaybeDownloadArgs {
|
||||
name_or_description_of_file: "vits traced tts model",
|
||||
final_filesystem_file_path: &vits_traced_synthesizer_fs_path,
|
||||
bucket_object_path: &vits_traced_synthesizer_object_path,
|
||||
bucket_client: &args.job_dependencies.buckets.private_bucket_client,
|
||||
job_progress_reporter: &mut job_progress_reporter,
|
||||
job_progress_update_description: "downloading synthesizer",
|
||||
job_id: job.id.0,
|
||||
scoped_tempdir_creator: &args.job_dependencies.fs.scoped_temp_dir_creator_for_short_lived_downloads,
|
||||
maybe_existing_file_minimum_size_required: None,
|
||||
}).await?;
|
||||
|
||||
vits_traced_synthesizer_fs_path
|
||||
};
|
||||
|
||||
+3
-3
@@ -4,12 +4,12 @@ use anyhow::anyhow;
|
||||
use log::{error, info};
|
||||
|
||||
use cloud_storage::bucket_client::BucketClient;
|
||||
use container_common::filesystem::safe_delete_temp_directory::safe_delete_temp_directory;
|
||||
use errors::AnyhowResult;
|
||||
use filesys::create_dir_all_if_missing::create_dir_all_if_missing;
|
||||
use filesys::file_exists::file_exists;
|
||||
use filesys::rename_across_devices::rename_across_devices;
|
||||
use filesys::safe_delete_temp_directory::safe_delete_temp_directory;
|
||||
|
||||
use crate::job::job_loop::process_single_job_error::ProcessSingleJobError;
|
||||
use crate::util::scoped_temp_dir_creator::ScopedTempDirCreator;
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -43,7 +43,7 @@ impl PretrainedHubertModel {
|
||||
&self,
|
||||
bucket_client: &BucketClient,
|
||||
scoped_tempdir_creator: &ScopedTempDirCreator,
|
||||
) -> AnyhowResult<()> {
|
||||
) -> Result<(), ProcessSingleJobError> {
|
||||
if file_exists(&self.filesystem_path) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use std::fs::read_to_string;
|
||||
use std::path::PathBuf;
|
||||
use std::time::Instant;
|
||||
|
||||
@@ -6,12 +7,12 @@ use log::{error, info, warn};
|
||||
|
||||
use buckets::public::media_files::original_file::MediaFileBucketPath;
|
||||
use buckets::public::media_uploads::original_file::MediaUploadOriginalFilePath;
|
||||
use container_common::filesystem::check_file_exists::check_file_exists;
|
||||
use container_common::filesystem::safe_delete_temp_directory::safe_delete_temp_directory;
|
||||
use container_common::filesystem::safe_delete_temp_file::safe_delete_temp_file;
|
||||
use enums::by_table::generic_inference_jobs::inference_result_type::InferenceResultType;
|
||||
use filesys::check_file_exists::check_file_exists;
|
||||
use filesys::create_dir_all_if_missing::create_dir_all_if_missing;
|
||||
use filesys::file_size::file_size;
|
||||
use filesys::safe_delete_temp_directory::safe_delete_temp_directory;
|
||||
use filesys::safe_delete_temp_file::safe_delete_temp_file;
|
||||
use hashing::sha256::sha256_hash_file::sha256_hash_file;
|
||||
use media::decode_basic_audio_info::decode_basic_audio_file_info;
|
||||
use mimetypes::mimetype_for_file::get_mimetype_for_file;
|
||||
@@ -27,7 +28,7 @@ use crate::job::job_loop::job_success_result::{JobSuccessResult, ResultEntity};
|
||||
use crate::job::job_loop::process_single_job_error::ProcessSingleJobError;
|
||||
use crate::job::job_types::vc::rvc_v2::rvc_v2_inference_command::InferenceArgs;
|
||||
use crate::job_dependencies::JobDependencies;
|
||||
use crate::util::maybe_download_file_from_bucket::maybe_download_file_from_bucket;
|
||||
use crate::util::maybe_download_file_from_bucket::{maybe_download_file_from_bucket, MaybeDownloadArgs};
|
||||
|
||||
const BUCKET_FILE_PREFIX : &str = "fakeyou_rvc_";
|
||||
const BUCKET_FILE_EXTENSION : &str = ".wav";
|
||||
@@ -64,11 +65,11 @@ pub async fn process_job(args: RvcV2ProcessJobArgs<'_>) -> Result<JobSuccessResu
|
||||
|
||||
model_dependencies.pretrained_hubert_model.download_if_not_on_filesystem(
|
||||
&args.job_dependencies.buckets.private_bucket_client,
|
||||
&args.job_dependencies.fs.scoped_temp_dir_creator_for_downloads)
|
||||
&args.job_dependencies.fs.scoped_temp_dir_creator_for_short_lived_downloads)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
error!("could not download hubert: {:?}", e);
|
||||
ProcessSingleJobError::from_anyhow_error(e)
|
||||
.map_err(|err| {
|
||||
error!("could not download hubert: {:?}", err);
|
||||
err
|
||||
})?;
|
||||
|
||||
// ==================== CONFIRM OR DOWNLOAD RVC (v2) MODEL ==================== //
|
||||
@@ -87,16 +88,17 @@ pub async fn process_job(args: RvcV2ProcessJobArgs<'_>) -> Result<JobSuccessResu
|
||||
|
||||
let model_object_path = args.job_dependencies.buckets.bucket_path_unifier.rvc_v2_model_path(&vc_model.private_bucket_hash);
|
||||
|
||||
maybe_download_file_from_bucket(
|
||||
"rvc (v2) model",
|
||||
&fs_path,
|
||||
&model_object_path,
|
||||
&args.job_dependencies.buckets.private_bucket_client,
|
||||
&mut job_progress_reporter,
|
||||
"downloading rvc (v2) model",
|
||||
job.id.0,
|
||||
&args.job_dependencies.fs.scoped_temp_dir_creator_for_downloads,
|
||||
).await?;
|
||||
maybe_download_file_from_bucket(MaybeDownloadArgs {
|
||||
name_or_description_of_file: "rvc (v2) model",
|
||||
final_filesystem_file_path: &fs_path,
|
||||
bucket_object_path: &model_object_path,
|
||||
bucket_client: &args.job_dependencies.buckets.private_bucket_client,
|
||||
job_progress_reporter: &mut job_progress_reporter,
|
||||
job_progress_update_description: "downloading rvc (v2) model",
|
||||
job_id: job.id.0,
|
||||
scoped_tempdir_creator: &args.job_dependencies.fs.scoped_temp_dir_creator_for_short_lived_downloads,
|
||||
maybe_existing_file_minimum_size_required: None,
|
||||
}).await?;
|
||||
|
||||
fs_path
|
||||
};
|
||||
@@ -113,12 +115,12 @@ pub async fn process_job(args: RvcV2ProcessJobArgs<'_>) -> Result<JobSuccessResu
|
||||
|
||||
let result = downloader.download_if_not_on_filesystem(
|
||||
&args.job_dependencies.buckets.private_bucket_client,
|
||||
&args.job_dependencies.fs.scoped_temp_dir_creator_for_downloads,
|
||||
&args.job_dependencies.fs.scoped_temp_dir_creator_for_short_lived_downloads,
|
||||
).await;
|
||||
|
||||
if let Err(e) = result {
|
||||
error!("could not download: {:?}", e);
|
||||
return Err(ProcessSingleJobError::from_anyhow_error(e))
|
||||
if let Err(err) = result {
|
||||
error!("could not download: {:?}", err);
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,16 +144,17 @@ pub async fn process_job(args: RvcV2ProcessJobArgs<'_>) -> Result<JobSuccessResu
|
||||
|
||||
let model_index_object_path = args.job_dependencies.buckets.bucket_path_unifier.rvc_v2_model_index_path(&vc_model.private_bucket_hash);
|
||||
|
||||
maybe_download_file_from_bucket(
|
||||
"rvc (v2) model index",
|
||||
&fs_path,
|
||||
&model_index_object_path,
|
||||
&args.job_dependencies.buckets.private_bucket_client,
|
||||
&mut job_progress_reporter,
|
||||
"downloading rvc (v2) model index",
|
||||
job.id.0,
|
||||
&args.job_dependencies.fs.scoped_temp_dir_creator_for_downloads,
|
||||
).await?;
|
||||
maybe_download_file_from_bucket(MaybeDownloadArgs {
|
||||
name_or_description_of_file: "rvc (v2) model index",
|
||||
final_filesystem_file_path: &fs_path,
|
||||
bucket_object_path: &model_index_object_path,
|
||||
bucket_client: &args.job_dependencies.buckets.private_bucket_client,
|
||||
job_progress_reporter: &mut job_progress_reporter,
|
||||
job_progress_update_description: "downloading rvc (v2) model index",
|
||||
job_id: job.id.0,
|
||||
scoped_tempdir_creator: &args.job_dependencies.fs.scoped_temp_dir_creator_for_short_lived_downloads,
|
||||
maybe_existing_file_minimum_size_required: None,
|
||||
}).await?;
|
||||
|
||||
Some(fs_path)
|
||||
};
|
||||
@@ -185,16 +188,17 @@ pub async fn process_job(args: RvcV2ProcessJobArgs<'_>) -> Result<JobSuccessResu
|
||||
|
||||
info!("Downloading media from bucket path: {:?}", &bucket_object_path);
|
||||
|
||||
maybe_download_file_from_bucket(
|
||||
"media upload (original file)",
|
||||
&original_media_upload_fs_path,
|
||||
&bucket_object_path,
|
||||
&args.job_dependencies.buckets.public_bucket_client,
|
||||
&mut job_progress_reporter,
|
||||
"downloading",
|
||||
job.id.0,
|
||||
&args.job_dependencies.fs.scoped_temp_dir_creator_for_work,
|
||||
).await?;
|
||||
maybe_download_file_from_bucket(MaybeDownloadArgs {
|
||||
name_or_description_of_file: "media upload (original file)",
|
||||
final_filesystem_file_path: &original_media_upload_fs_path,
|
||||
bucket_object_path: &bucket_object_path,
|
||||
bucket_client: &args.job_dependencies.buckets.public_bucket_client,
|
||||
job_progress_reporter: &mut job_progress_reporter,
|
||||
job_progress_update_description: "downloading",
|
||||
job_id: job.id.0,
|
||||
scoped_tempdir_creator: &args.job_dependencies.fs.scoped_temp_dir_creator_for_work,
|
||||
maybe_existing_file_minimum_size_required: None,
|
||||
}).await?;
|
||||
|
||||
original_media_upload_fs_path
|
||||
};
|
||||
@@ -217,6 +221,8 @@ pub async fn process_job(args: RvcV2ProcessJobArgs<'_>) -> Result<JobSuccessResu
|
||||
//let output_metadata_fs_path = temp_dir.path().join("metadata.json");
|
||||
//let output_spectrogram_fs_path = temp_dir.path().join("spectrogram.json");
|
||||
|
||||
let stderr_output_file = work_temp_dir.path().join("stderr.txt");
|
||||
|
||||
info!("Running RVC (v2) VC inference...");
|
||||
|
||||
info!("Expected output audio filename: {:?}", &output_audio_fs_path);
|
||||
@@ -257,6 +263,7 @@ pub async fn process_job(args: RvcV2ProcessJobArgs<'_>) -> Result<JobSuccessResu
|
||||
rmvpe_path: &model_dependencies.downloaders.rmvpe.filesystem_path,
|
||||
input_path: &input_wav_path,
|
||||
output_path: &output_audio_fs_path,
|
||||
stderr_output_file: &stderr_output_file,
|
||||
maybe_override_f0_method,
|
||||
maybe_f0_up_key,
|
||||
});
|
||||
@@ -267,10 +274,26 @@ pub async fn process_job(args: RvcV2ProcessJobArgs<'_>) -> Result<JobSuccessResu
|
||||
|
||||
if !command_exit_status.is_success() {
|
||||
error!("Inference failed: {:?}", command_exit_status);
|
||||
|
||||
let error = ProcessSingleJobError::Other(anyhow!("CommandExitStatus: {:?}", command_exit_status));
|
||||
|
||||
if let Ok(contents) = read_to_string(&stderr_output_file) {
|
||||
warn!("Captured stderr output: {}", contents);
|
||||
|
||||
//match categorize_error(&contents) {
|
||||
// Some(ProcessSingleJobError::FaceDetectionFailure) => {
|
||||
// warn!("Face not detected in source image");
|
||||
// error = ProcessSingleJobError::FaceDetectionFailure;
|
||||
// }
|
||||
// _ => {}
|
||||
//}
|
||||
}
|
||||
|
||||
safe_delete_temp_file(&input_wav_path);
|
||||
safe_delete_temp_file(&output_audio_fs_path);
|
||||
safe_delete_temp_directory(&work_temp_dir);
|
||||
return Err(ProcessSingleJobError::Other(anyhow!("CommandExitStatus: {:?}", command_exit_status)));
|
||||
|
||||
return Err(error);
|
||||
}
|
||||
|
||||
// ==================== CHECK ALL FILES EXIST AND GET METADATA ==================== //
|
||||
|
||||
+10
-2
@@ -1,15 +1,16 @@
|
||||
use std::collections::HashSet;
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::fs::File;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::anyhow;
|
||||
use log::info;
|
||||
use once_cell::sync::Lazy;
|
||||
use subprocess::{Popen, PopenConfig};
|
||||
use subprocess::{Popen, PopenConfig, Redirection};
|
||||
|
||||
use container_common::anyhow_result::AnyhowResult;
|
||||
use errors::AnyhowResult;
|
||||
use filesys::path_to_string::path_to_string;
|
||||
use mysql_queries::payloads::generic_inference_args::generic_inference_args::FundamentalFrequencyMethodForJob;
|
||||
use subprocess_common::docker_options::{DockerFilesystemMount, DockerGpu, DockerOptions};
|
||||
@@ -80,6 +81,8 @@ pub struct InferenceArgs<P: AsRef<Path>, Q: AsRef<Path>> {
|
||||
/// --output_audio_filename: output path of wav file.
|
||||
pub output_path: P,
|
||||
|
||||
pub stderr_output_file: P,
|
||||
|
||||
/// --f0-method: f0 prediction method
|
||||
pub maybe_override_f0_method: Option<FundamentalFrequencyMethodForJob>,
|
||||
|
||||
@@ -267,6 +270,11 @@ impl RvcV2InferenceCommand {
|
||||
|
||||
let mut config = PopenConfig::default();
|
||||
|
||||
info!("stderr will be written to file: {:?}", args.stderr_output_file.as_ref());
|
||||
|
||||
let stderr_file = File::create(&args.stderr_output_file)?;
|
||||
config.stderr = Redirection::File(stderr_file);
|
||||
|
||||
if !env_vars.is_empty() {
|
||||
config.env = Some(env_vars);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use std::fs::read_to_string;
|
||||
use std::time::Instant;
|
||||
|
||||
use anyhow::anyhow;
|
||||
@@ -5,12 +6,12 @@ use log::{error, info, warn};
|
||||
|
||||
use buckets::public::media_files::original_file::MediaFileBucketPath;
|
||||
use buckets::public::media_uploads::original_file::MediaUploadOriginalFilePath;
|
||||
use container_common::filesystem::check_file_exists::check_file_exists;
|
||||
use container_common::filesystem::safe_delete_temp_directory::safe_delete_temp_directory;
|
||||
use container_common::filesystem::safe_delete_temp_file::safe_delete_temp_file;
|
||||
use enums::by_table::generic_inference_jobs::inference_result_type::InferenceResultType;
|
||||
use filesys::check_file_exists::check_file_exists;
|
||||
use filesys::create_dir_all_if_missing::create_dir_all_if_missing;
|
||||
use filesys::file_size::file_size;
|
||||
use filesys::safe_delete_temp_directory::safe_delete_temp_directory;
|
||||
use filesys::safe_delete_temp_file::safe_delete_temp_file;
|
||||
use hashing::sha256::sha256_hash_file::sha256_hash_file;
|
||||
use media::decode_basic_audio_info::decode_basic_audio_file_info;
|
||||
use mimetypes::mimetype_for_file::get_mimetype_for_file;
|
||||
@@ -26,7 +27,7 @@ use crate::job::job_loop::job_success_result::{JobSuccessResult, ResultEntity};
|
||||
use crate::job::job_loop::process_single_job_error::ProcessSingleJobError;
|
||||
use crate::job::job_types::vc::so_vits_svc::so_vits_svc_inference_command::{Device, InferenceArgs};
|
||||
use crate::job_dependencies::JobDependencies;
|
||||
use crate::util::maybe_download_file_from_bucket::maybe_download_file_from_bucket;
|
||||
use crate::util::maybe_download_file_from_bucket::{maybe_download_file_from_bucket, MaybeDownloadArgs};
|
||||
|
||||
const BUCKET_FILE_PREFIX : &str = "fakeyou_svc_";
|
||||
const BUCKET_FILE_EXTENSION : &str = ".wav";
|
||||
@@ -76,16 +77,17 @@ pub async fn process_job(args: SoVitsSvcProcessJobArgs<'_>) -> Result<JobSuccess
|
||||
|
||||
let so_vits_svc_model_object_path = args.job_dependencies.buckets.bucket_path_unifier.so_vits_svc_model_path(&vc_model.private_bucket_hash);
|
||||
|
||||
maybe_download_file_from_bucket(
|
||||
"so-vits-svc model",
|
||||
&so_vits_svc_fs_path,
|
||||
&so_vits_svc_model_object_path,
|
||||
&args.job_dependencies.buckets.private_bucket_client,
|
||||
&mut job_progress_reporter,
|
||||
"downloading so-vits-svc model",
|
||||
job.id.0,
|
||||
&args.job_dependencies.fs.scoped_temp_dir_creator_for_downloads,
|
||||
).await?;
|
||||
maybe_download_file_from_bucket(MaybeDownloadArgs {
|
||||
name_or_description_of_file: "so-vits-svc model",
|
||||
final_filesystem_file_path: &so_vits_svc_fs_path,
|
||||
bucket_object_path: &so_vits_svc_model_object_path,
|
||||
bucket_client: &args.job_dependencies.buckets.private_bucket_client,
|
||||
job_progress_reporter: &mut job_progress_reporter,
|
||||
job_progress_update_description: "downloading so-vits-svc model",
|
||||
job_id: job.id.0,
|
||||
scoped_tempdir_creator: &args.job_dependencies.fs.scoped_temp_dir_creator_for_short_lived_downloads,
|
||||
maybe_existing_file_minimum_size_required: None,
|
||||
}).await?;
|
||||
|
||||
so_vits_svc_fs_path
|
||||
};
|
||||
@@ -118,16 +120,17 @@ pub async fn process_job(args: SoVitsSvcProcessJobArgs<'_>) -> Result<JobSuccess
|
||||
|
||||
info!("Downloading media to bucket path: {:?}", &bucket_object_path);
|
||||
|
||||
maybe_download_file_from_bucket(
|
||||
"media upload (original file)",
|
||||
&original_media_upload_fs_path,
|
||||
&bucket_object_path,
|
||||
&args.job_dependencies.buckets.public_bucket_client,
|
||||
&mut job_progress_reporter,
|
||||
"downloading",
|
||||
job.id.0,
|
||||
&args.job_dependencies.fs.scoped_temp_dir_creator_for_work,
|
||||
).await?;
|
||||
maybe_download_file_from_bucket(MaybeDownloadArgs {
|
||||
name_or_description_of_file: "media upload (original file)",
|
||||
final_filesystem_file_path: &original_media_upload_fs_path,
|
||||
bucket_object_path: &bucket_object_path,
|
||||
bucket_client: &args.job_dependencies.buckets.public_bucket_client,
|
||||
job_progress_reporter: &mut job_progress_reporter,
|
||||
job_progress_update_description: "downloading",
|
||||
job_id: job.id.0,
|
||||
scoped_tempdir_creator: &args.job_dependencies.fs.scoped_temp_dir_creator_for_work,
|
||||
maybe_existing_file_minimum_size_required: None,
|
||||
}).await?;
|
||||
|
||||
original_media_upload_fs_path
|
||||
};
|
||||
@@ -146,6 +149,8 @@ pub async fn process_job(args: SoVitsSvcProcessJobArgs<'_>) -> Result<JobSuccess
|
||||
|
||||
let output_audio_fs_path = work_temp_dir.path().join("output.wav");
|
||||
|
||||
let stderr_output_file = work_temp_dir.path().join("stderr.txt");
|
||||
|
||||
info!("Running VC inference...");
|
||||
|
||||
info!("Expected output audio filename: {:?}", &output_audio_fs_path);
|
||||
@@ -185,6 +190,7 @@ pub async fn process_job(args: SoVitsSvcProcessJobArgs<'_>) -> Result<JobSuccess
|
||||
model_path: &so_vits_svc_fs_path,
|
||||
input_path: &input_wav_path,
|
||||
output_path: &output_audio_fs_path,
|
||||
stderr_output_file: &stderr_output_file,
|
||||
maybe_config_path: None,
|
||||
device: Device::Cuda,
|
||||
auto_predict_f0,
|
||||
@@ -197,10 +203,26 @@ pub async fn process_job(args: SoVitsSvcProcessJobArgs<'_>) -> Result<JobSuccess
|
||||
|
||||
if !command_exit_status.is_success() {
|
||||
error!("Inference failed: {:?}", command_exit_status);
|
||||
|
||||
let error = ProcessSingleJobError::Other(anyhow!("CommandExitStatus: {:?}", command_exit_status));
|
||||
|
||||
if let Ok(contents) = read_to_string(&stderr_output_file) {
|
||||
warn!("Captured stderr output: {}", contents);
|
||||
|
||||
//match categorize_error(&contents) {
|
||||
// Some(ProcessSingleJobError::FaceDetectionFailure) => {
|
||||
// warn!("Face not detected in source image");
|
||||
// error = ProcessSingleJobError::FaceDetectionFailure;
|
||||
// }
|
||||
// _ => {}
|
||||
//}
|
||||
}
|
||||
|
||||
safe_delete_temp_file(&input_wav_path);
|
||||
safe_delete_temp_file(&output_audio_fs_path);
|
||||
safe_delete_temp_directory(&work_temp_dir);
|
||||
return Err(ProcessSingleJobError::Other(anyhow!("CommandExitStatus: {:?}", command_exit_status)));
|
||||
|
||||
return Err(error);
|
||||
}
|
||||
|
||||
// ==================== CHECK ALL FILES EXIST AND GET METADATA ==================== //
|
||||
|
||||
+10
-2
@@ -1,15 +1,16 @@
|
||||
use std::collections::HashSet;
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::fs::File;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::anyhow;
|
||||
use log::info;
|
||||
use once_cell::sync::Lazy;
|
||||
use subprocess::{Popen, PopenConfig};
|
||||
use subprocess::{Popen, PopenConfig, Redirection};
|
||||
|
||||
use container_common::anyhow_result::AnyhowResult;
|
||||
use errors::AnyhowResult;
|
||||
use filesys::path_to_string::path_to_string;
|
||||
use subprocess_common::docker_options::{DockerEnvVar, DockerFilesystemMount, DockerGpu, DockerOptions};
|
||||
|
||||
@@ -90,6 +91,8 @@ pub struct InferenceArgs<P: AsRef<Path>> {
|
||||
/// --output_path: output path of converting model to onnx (which we use to test validity)
|
||||
pub output_path: P,
|
||||
|
||||
pub stderr_output_file: P,
|
||||
|
||||
/// --auto-predict-f0: turn on or off fundamental frequency auto prediction
|
||||
/// This sounds better when left off, but it defaults to *ON* if not specified.
|
||||
pub auto_predict_f0: bool,
|
||||
@@ -366,6 +369,11 @@ impl SoVitsSvcInferenceCommand {
|
||||
|
||||
let mut config = PopenConfig::default();
|
||||
|
||||
info!("stderr will be written to file: {:?}", args.stderr_output_file.as_ref());
|
||||
|
||||
let stderr_file = File::create(&args.stderr_output_file)?;
|
||||
config.stderr = Redirection::File(stderr_file);
|
||||
|
||||
if !env_vars.is_empty() {
|
||||
config.env = Some(env_vars);
|
||||
}
|
||||
|
||||
@@ -60,6 +60,10 @@ pub struct JobSystemControls {
|
||||
/// This is provided at job start.
|
||||
pub scoped_execution: ScopedExecution,
|
||||
|
||||
// Allow for models not to exist on the filesystem. All jobs will execute when first tried
|
||||
// regardless of whether their models were previously downloaded.
|
||||
pub always_allow_cold_filesystem_cache: bool,
|
||||
|
||||
// How many times to skip jobs (on cold filesystem cache) before proceeding with execution.
|
||||
pub cold_filesystem_cache_starvation_threshold: u64,
|
||||
|
||||
@@ -138,27 +142,27 @@ pub struct ClientDependencies {
|
||||
}
|
||||
|
||||
pub struct FileSystemDetails {
|
||||
/// Temporary directory for storing downloads
|
||||
/// (In prod, typically model files from GCS / NFS PVC mount)
|
||||
pub temp_directory_downloads: PathBuf,
|
||||
|
||||
/// Temporary directory for storing work
|
||||
/// (In prod, typically python inference outputs / emptyDir mount)
|
||||
pub temp_directory_work: PathBuf,
|
||||
|
||||
/// If the pause file is set and exists on the filesystem,
|
||||
/// the job will pause until the file stops existing.
|
||||
/// Good for live debugging of production k8s clusters without
|
||||
/// redeploying.
|
||||
pub maybe_pause_file: Option<PathBuf>,
|
||||
|
||||
// TODO: Rename
|
||||
/// Temporary directory for storing downloads
|
||||
/// Creates temp directories for scratch files
|
||||
pub scoped_temp_dir_creator_for_downloads: ScopedTempDirCreator,
|
||||
pub scoped_temp_dir_creator_for_short_lived_downloads: ScopedTempDirCreator,
|
||||
|
||||
/// Temporary directory for storing downloads
|
||||
/// (In prod, typically model files from GCS / NFS PVC mount)
|
||||
pub scoped_temp_dir_creator_for_long_lived_downloads: ScopedTempDirCreator,
|
||||
|
||||
/// Temporary directory for storing work
|
||||
/// (In prod, typically python inference outputs / emptyDir mount)
|
||||
pub scoped_temp_dir_creator_for_work: ScopedTempDirCreator,
|
||||
|
||||
// TODO: Rename
|
||||
/// Organizes downloaded files
|
||||
/// Directory to store long-term downloads (models)
|
||||
/// (In prod, typically model files from GCS / NFS PVC mount)
|
||||
pub semi_persistent_cache: SemiPersistentCacheDir,
|
||||
}
|
||||
|
||||
|
||||
@@ -32,8 +32,8 @@ use concurrency::relaxed_atomic_bool::RelaxedAtomicBool;
|
||||
use config::common_env::CommonEnv;
|
||||
use config::shared_constants::DEFAULT_MYSQL_CONNECTION_STRING;
|
||||
use config::shared_constants::DEFAULT_RUST_LOG;
|
||||
use container_common::anyhow_result::AnyhowResult;
|
||||
use container_common::filesystem::check_directory_exists::check_directory_exists;
|
||||
use errors::AnyhowResult;
|
||||
use filesys::check_directory_exists::check_directory_exists;
|
||||
use filesys::create_dir_all_if_missing::create_dir_all_if_missing;
|
||||
use jobs_common::job_progress_reporter::job_progress_reporter::JobProgressReporterBuilder;
|
||||
use jobs_common::job_progress_reporter::noop_job_progress_reporter::NoOpJobProgressReporterBuilder;
|
||||
@@ -119,35 +119,10 @@ async fn main() -> AnyhowResult<()> {
|
||||
)?;
|
||||
|
||||
// Where we download models and resources to (typically a shared NFS volume in prod).
|
||||
let temp_directory_downloads = easyenv::get_env_pathbuf_or_default(
|
||||
"TEMP_DIR_DOWNLOADS",
|
||||
PathBuf::from("/tmp/downloads")
|
||||
);
|
||||
|
||||
// Where we store scratch files for workloads (temporary processing).
|
||||
let temp_directory_work = easyenv::get_env_pathbuf_or_default(
|
||||
"TEMP_DIR_WORK",
|
||||
PathBuf::from("/tmp/work")
|
||||
);
|
||||
|
||||
if !container_environment.server_environment.is_deployed_in_production() {
|
||||
warn!("Creating temporary directories for non-production / development only!");
|
||||
create_dir_all_if_missing(&temp_directory_downloads)?;
|
||||
create_dir_all_if_missing(&temp_directory_work)?;
|
||||
}
|
||||
|
||||
check_directory_exists(&temp_directory_downloads)?;
|
||||
check_directory_exists(&temp_directory_work)?;
|
||||
|
||||
let semi_persistent_cache =
|
||||
SemiPersistentCacheDir::configured_root(&temp_directory_downloads);
|
||||
|
||||
// TODO(bt,2023.05.22): create_all_paths() for some subset of jobs.
|
||||
info!("Creating pod semi-persistent cache dirs...");
|
||||
semi_persistent_cache.create_custom_vocoder_model_path()?;
|
||||
semi_persistent_cache.create_tts_pretrained_vocoder_model_path()?;
|
||||
semi_persistent_cache.create_tts_synthesizer_model_path()?;
|
||||
semi_persistent_cache.create_voice_conversion_model_path()?;
|
||||
let semi_persistent_cache = SemiPersistentCacheDir::configured_root(
|
||||
easyenv::get_env_pathbuf_or_default("SEMI_PERSISTENT_DIR_ROOT",
|
||||
PathBuf::from("/tmp/persistent")));
|
||||
|
||||
let db_connection_string =
|
||||
easyenv::get_env_string_or_default(
|
||||
@@ -242,11 +217,16 @@ async fn main() -> AnyhowResult<()> {
|
||||
maybe_keepalive_redis_pool,
|
||||
},
|
||||
fs: FileSystemDetails {
|
||||
temp_directory_downloads: temp_directory_downloads.clone(),
|
||||
temp_directory_work: temp_directory_work.clone(),
|
||||
maybe_pause_file: easyenv::get_env_pathbuf_optional("PAUSE_FILE"),
|
||||
scoped_temp_dir_creator_for_downloads: ScopedTempDirCreator::for_directory(&temp_directory_downloads),
|
||||
scoped_temp_dir_creator_for_work: ScopedTempDirCreator::for_directory(&temp_directory_work),
|
||||
scoped_temp_dir_creator_for_short_lived_downloads: ScopedTempDirCreator::for_directory(
|
||||
easyenv::get_env_pathbuf_or_default(
|
||||
"SCOPED_TEMP_DIR_SHORT_LIVED_DOWNLOADS", PathBuf::from("/tmp/downloads_short_lived"))),
|
||||
scoped_temp_dir_creator_for_long_lived_downloads: ScopedTempDirCreator::for_directory(
|
||||
easyenv::get_env_pathbuf_or_default(
|
||||
"SCOPED_TEMP_DIR_LONG_LIVED_DOWNLOADS", PathBuf::from("/tmp/downloads_long_lived"))),
|
||||
scoped_temp_dir_creator_for_work: ScopedTempDirCreator::for_directory(
|
||||
easyenv::get_env_pathbuf_or_default(
|
||||
"SCOPED_TEMP_DIR_WORK", PathBuf::from("/tmp/downloads_long_lived"))),
|
||||
semi_persistent_cache,
|
||||
},
|
||||
buckets: BucketDependencies {
|
||||
@@ -263,6 +243,7 @@ async fn main() -> AnyhowResult<()> {
|
||||
job: JobSystemDependencies {
|
||||
system: JobSystemControls {
|
||||
scoped_execution,
|
||||
always_allow_cold_filesystem_cache: easyenv::get_env_bool_or_default("ALWAYS_ALLOW_COLD_FILESYSTEM_CACHE", false),
|
||||
cold_filesystem_cache_starvation_threshold: easyenv::get_env_num("COLD_FILESYSTEM_CACHE_STARVATION_THRESHOLD", 3)?,
|
||||
job_batch_wait_millis: common_env.job_batch_wait_millis,
|
||||
job_max_attempts: common_env.job_max_attempts as u16,
|
||||
@@ -306,6 +287,8 @@ async fn main() -> AnyhowResult<()> {
|
||||
},
|
||||
};
|
||||
|
||||
set_up_directories(&job_dependencies)?;
|
||||
|
||||
std::thread::spawn(move || {
|
||||
let actix_runtime = actix_web::rt::System::new();
|
||||
let http_server_handle = launch_http_server(create_server_args);
|
||||
@@ -322,3 +305,30 @@ async fn main() -> AnyhowResult<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_up_directories(job_dependencies: &JobDependencies) -> AnyhowResult<()> {
|
||||
info!("Setting up and checking file system paths for temporary work, ephemeral and persistent downloads, etc...");
|
||||
|
||||
let fs = &job_dependencies.fs;
|
||||
|
||||
if !job_dependencies.job.info.container.server_environment.is_deployed_in_production() {
|
||||
warn!("Creating directories for non-production / development only!");
|
||||
|
||||
create_dir_all_if_missing(&fs.scoped_temp_dir_creator_for_long_lived_downloads.get_base_dir())?;
|
||||
create_dir_all_if_missing(&fs.scoped_temp_dir_creator_for_short_lived_downloads.get_base_dir())?;
|
||||
create_dir_all_if_missing(&fs.scoped_temp_dir_creator_for_work.get_base_dir())?;
|
||||
}
|
||||
|
||||
check_directory_exists(fs.scoped_temp_dir_creator_for_long_lived_downloads.get_base_dir())?;
|
||||
check_directory_exists(fs.scoped_temp_dir_creator_for_short_lived_downloads.get_base_dir())?;
|
||||
check_directory_exists(fs.scoped_temp_dir_creator_for_work.get_base_dir())?;
|
||||
|
||||
// TODO(bt,2023.05.22): create_all_paths() for some subset of jobs.
|
||||
info!("Creating semi-persistent cache dirs...");
|
||||
|
||||
fs.semi_persistent_cache.create_custom_vocoder_model_path()?;
|
||||
fs.semi_persistent_cache.create_tts_pretrained_vocoder_model_path()?;
|
||||
fs.semi_persistent_cache.create_tts_synthesizer_model_path()?;
|
||||
fs.semi_persistent_cache.create_voice_conversion_model_path()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ use log::{info, warn};
|
||||
use once_cell::sync::Lazy;
|
||||
use subprocess::{Popen, PopenConfig};
|
||||
|
||||
use container_common::anyhow_result::AnyhowResult;
|
||||
use errors::AnyhowResult;
|
||||
use filesys::path_to_string::path_to_string;
|
||||
|
||||
use crate::job::job_loop::command_exit_status::CommandExitStatus;
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
use std::io;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use errors::AnyhowResult;
|
||||
use filesys::check_directory_exists::check_directory_exists;
|
||||
use filesys::create_dir_all_if_missing::create_dir_all_if_missing;
|
||||
|
||||
/// Utilities for directories serving as file caches
|
||||
#[derive(Clone)]
|
||||
pub struct FileCacheDir {
|
||||
directory: PathBuf
|
||||
}
|
||||
|
||||
impl FileCacheDir {
|
||||
pub fn from_env<P: AsRef<Path>>(env_var_name: &str, default_path: P) -> AnyhowResult<Self> {
|
||||
Ok(Self {
|
||||
directory: easyenv::get_env_pathbuf_or_default(env_var_name, default_path),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn create_dir_all_if_missing(&self) -> std::io::Result<()> {
|
||||
create_dir_all_if_missing(&self.directory)
|
||||
}
|
||||
|
||||
pub fn err_unless_exists(&self) -> AnyhowResult<()> {
|
||||
check_directory_exists(&self.directory)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn as_path(&self) -> &Path {
|
||||
&self.directory
|
||||
}
|
||||
|
||||
/// Return the number of files in the directory (non-recursive).
|
||||
/// If there is a concern for a long-running list operation, a `max_count` can be returned.
|
||||
pub fn file_count(&self, maybe_max_count: Option<usize>) -> io::Result<usize> {
|
||||
let mut count = 0;
|
||||
// NB: Two for loops to prevent if-checks in optimized loop case.
|
||||
if let Some(max_count) = maybe_max_count {
|
||||
for entry in std::fs::read_dir(&self.directory)? {
|
||||
let _entry = entry?;
|
||||
if max_count > count {
|
||||
return Ok(max_count);
|
||||
}
|
||||
count += 1;
|
||||
}
|
||||
} else {
|
||||
for entry in std::fs::read_dir(&self.directory)? {
|
||||
let _entry = entry?;
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
Ok(count)
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,12 @@
|
||||
use std::path::Path;
|
||||
|
||||
use log::{info, warn};
|
||||
use log::{error, info, warn};
|
||||
|
||||
use cloud_storage::bucket_client::BucketClient;
|
||||
use container_common::filesystem::safe_delete_temp_directory::safe_delete_temp_directory;
|
||||
use filesys::file_size::file_size;
|
||||
use filesys::rename_across_devices::{rename_across_devices, RenameError};
|
||||
use filesys::safe_delete_temp_directory::safe_delete_temp_directory;
|
||||
use filesys::safe_delete_temp_file::safe_delete_temp_file;
|
||||
use jobs_common::job_progress_reporter::job_progress_reporter::JobProgressReporter;
|
||||
|
||||
use crate::job::job_loop::process_single_job_error::ProcessSingleJobError;
|
||||
@@ -11,60 +14,204 @@ use crate::util::scoped_temp_dir_creator::ScopedTempDirCreator;
|
||||
|
||||
// TODO(bt, 2022-07-15): Make a concrete type for bucket paths
|
||||
|
||||
pub struct MaybeDownloadArgs<'a> {
|
||||
pub name_or_description_of_file: &'a str,
|
||||
pub final_filesystem_file_path: &'a Path,
|
||||
pub bucket_object_path: &'a Path,
|
||||
pub bucket_client: &'a BucketClient,
|
||||
pub job_progress_reporter: &'a mut Box<dyn JobProgressReporter>,
|
||||
pub job_progress_update_description: &'a str,
|
||||
pub job_id: i64,
|
||||
pub scoped_tempdir_creator: &'a ScopedTempDirCreator,
|
||||
pub maybe_existing_file_minimum_size_required: Option<u64>,
|
||||
}
|
||||
|
||||
pub async fn maybe_download_file_from_bucket(
|
||||
name_or_description_of_file: &str,
|
||||
file_path: &Path,
|
||||
bucket_object_path: &Path,
|
||||
bucket_client: &BucketClient,
|
||||
job_progress_reporter: &mut Box<dyn JobProgressReporter>,
|
||||
job_progress_update_description: &str,
|
||||
job_id: i64,
|
||||
scoped_tempdir_creator: &ScopedTempDirCreator,
|
||||
args: MaybeDownloadArgs<'_>
|
||||
) -> Result<(), ProcessSingleJobError> {
|
||||
|
||||
if file_path.exists() {
|
||||
// TODO(bt, 2022-07-15): Check signature of file
|
||||
return Ok(())
|
||||
if args.final_filesystem_file_path.exists() {
|
||||
// TODO(bt, 2022-07-15): Check signature of file as best proof of file validity
|
||||
let mut existing_file_is_valid = true;
|
||||
|
||||
if let Some(existing_file_minimum_size_required) = args.maybe_existing_file_minimum_size_required {
|
||||
// NB: Sometimes the downloader incompletely downloads files. Typically this is a zero file
|
||||
// size, but the Rust system may report a non-zero (but small) number of bytes. This should
|
||||
// later be investigated and the heuristic simplified. The intent here is merely to make sure
|
||||
// we don't consider these okay:
|
||||
//
|
||||
// -rw-r--r-- 1 root root 55824433 Nov 30 00:12 VM:012rkwsv91zb
|
||||
// -rw-r--r-- 1 root root 55823149 Nov 30 00:13 VM:79etbx4fdksv
|
||||
// -rw-r--r-- 1 root root 0 Nov 30 00:52 VM:1dzepsnwzbkc
|
||||
// -rw-r--r-- 1 root root 0 Nov 30 00:29 VM:7c2df5a36qjb
|
||||
//
|
||||
let size = file_size(args.final_filesystem_file_path)
|
||||
.map_err(|err| ProcessSingleJobError::from_anyhow_error(err))?;
|
||||
|
||||
info!("{} exists at path {:?} ; file size = {size}",
|
||||
&args.name_or_description_of_file,&args.final_filesystem_file_path);
|
||||
|
||||
if size < existing_file_minimum_size_required {
|
||||
existing_file_is_valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
if existing_file_is_valid {
|
||||
return Ok(())
|
||||
}
|
||||
} else {
|
||||
warn!("{} does not exist at path: {:?}", args.name_or_description_of_file, &args.final_filesystem_file_path);
|
||||
}
|
||||
|
||||
warn!("{} does not exist at path: {:?}", name_or_description_of_file, &file_path);
|
||||
|
||||
job_progress_reporter.log_status(job_progress_update_description)
|
||||
args.job_progress_reporter.log_status(args.job_progress_update_description)
|
||||
.map_err(|e| ProcessSingleJobError::Other(e))?;
|
||||
|
||||
// NB: Download to temp directory to stop concurrent writes and race conditions from other
|
||||
// workers writing to a shared volume.
|
||||
let temp_dir = format!("temp_download_{}", job_id);
|
||||
let temp_dir = format!("temp_download_{}", args.job_id);
|
||||
|
||||
// NB: TempDir exists until it goes out of scope, at which point it should delete from filesystem.
|
||||
let temp_dir = scoped_tempdir_creator.new_tempdir(&temp_dir)
|
||||
let temp_dir = args.scoped_tempdir_creator.new_tempdir(&temp_dir)
|
||||
.map_err(|e| ProcessSingleJobError::from_io_error(e))?;
|
||||
|
||||
let temp_path = temp_dir.path().join("download.part");
|
||||
|
||||
info!("Downloading {} from bucket path: {:?}", name_or_description_of_file, &bucket_object_path);
|
||||
info!("Downloading {} from bucket path: {:?}", args.name_or_description_of_file, &args.bucket_object_path);
|
||||
|
||||
bucket_client.download_file_to_disk(&bucket_object_path, &temp_path)
|
||||
args.bucket_client.download_file_to_disk(&args.bucket_object_path, &temp_path)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
safe_delete_temp_directory(&temp_dir);
|
||||
ProcessSingleJobError::Other(e)
|
||||
})?;
|
||||
|
||||
info!("Downloaded {} from bucket!", name_or_description_of_file);
|
||||
info!("Downloaded {} from bucket!", args.name_or_description_of_file);
|
||||
|
||||
let original_size = file_size(&temp_path)
|
||||
.map_err(|err| ProcessSingleJobError::from_anyhow_error(err))?;
|
||||
|
||||
info!("File size of {} temp download file {:?} is {original_size}",
|
||||
args.name_or_description_of_file, &temp_path);
|
||||
|
||||
info!("Renaming {} temp file from {:?} to {:?}!",
|
||||
name_or_description_of_file, &temp_path, &file_path);
|
||||
args.name_or_description_of_file, &temp_path, &args.final_filesystem_file_path);
|
||||
|
||||
std::fs::rename(&temp_path, &file_path)
|
||||
.map_err(|e| {
|
||||
rename_across_devices(&temp_path, &args.final_filesystem_file_path)
|
||||
.map_err(|err| {
|
||||
error!("could not rename on disk: {:?}", err);
|
||||
safe_delete_temp_file(&temp_path);
|
||||
safe_delete_temp_directory(&temp_dir);
|
||||
ProcessSingleJobError::from_io_error(e)
|
||||
match err {
|
||||
RenameError::StorageFull => ProcessSingleJobError::FilesystemFull,
|
||||
RenameError::IoError(err) => ProcessSingleJobError::from_io_error(err),
|
||||
}
|
||||
})?;
|
||||
|
||||
info!("Finished downloading {} file to {:?}", name_or_description_of_file, &file_path);
|
||||
// info!("Copying {} temp file from {:?} to {:?}!",
|
||||
// args.name_or_description_of_file, &temp_path, &args.final_filesystem_file_path);
|
||||
//
|
||||
// // NB: We're now seeing a bug where the resultant copied file is 0 bytes
|
||||
// match copy_with_logging(&temp_path, &args.final_filesystem_file_path) {
|
||||
// Err(err) => {
|
||||
// error!("Error Copying {} temp file from {:?} to {:?}! {err}",
|
||||
// args.name_or_description_of_file, &temp_path, &args.final_filesystem_file_path);
|
||||
//
|
||||
// safe_delete_temp_file(&temp_path);
|
||||
// safe_delete_temp_directory(&temp_dir);
|
||||
//
|
||||
// return Err(ProcessSingleJobError::from_anyhow_error(err));
|
||||
// }
|
||||
// Ok(false) => {
|
||||
// error!("Error copying {} temp file from {:?} to {:?}! File size in bytes did not match.",
|
||||
// args.name_or_description_of_file, &temp_path, &args.final_filesystem_file_path);
|
||||
//
|
||||
// reattempt_copy_if_failed(&args, &temp_dir, &temp_path, original_size)?;
|
||||
// }
|
||||
// Ok(true) => {
|
||||
// // Success case
|
||||
// }
|
||||
// }
|
||||
|
||||
info!("Finished downloading {} file to {:?}", args.name_or_description_of_file, &args.final_filesystem_file_path);
|
||||
|
||||
safe_delete_temp_file(&temp_path);
|
||||
safe_delete_temp_directory(&temp_dir);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// NB: Debugging failures with rename_across_devices() -
|
||||
// fn reattempt_copy_if_failed(args: &MaybeDownloadArgs, temp_dir: &TempDir, temp_path: &Path, original_size: u64) -> Result<(), ProcessSingleJobError> {
|
||||
// let copied_size = file_size(&args.final_filesystem_file_path)
|
||||
// .map_err(|err| ProcessSingleJobError::from_anyhow_error(err))?;
|
||||
//
|
||||
// info!("Final copied size of {} file {:?} is {copied_size} (original size was {original_size})",
|
||||
// args.name_or_description_of_file, &args.final_filesystem_file_path);
|
||||
//
|
||||
// if copied_size != 0 {
|
||||
// safe_delete_temp_file(&temp_path);
|
||||
// safe_delete_temp_directory(&temp_dir);
|
||||
//
|
||||
// return Ok(());
|
||||
// }
|
||||
//
|
||||
// error!("Copied size was 0! Removing destination file and retrying...");
|
||||
//
|
||||
// if let Err(err) = std::fs::remove_file(&args.final_filesystem_file_path) {
|
||||
// match err.kind() {
|
||||
// ErrorKind::NotFound => {
|
||||
// // NB: We seem to be seeing this in production.
|
||||
// // Perhaps another pod deleted it in a race condition?
|
||||
// // Fall through case.
|
||||
// warn!("File couldn't be removed: it's already gone.")
|
||||
// },
|
||||
// _ => {
|
||||
// safe_delete_temp_file(&temp_path);
|
||||
// safe_delete_temp_directory(&temp_dir);
|
||||
// return Err(ProcessSingleJobError::from_io_error(err));
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// warn!("File removed.");
|
||||
// }
|
||||
//
|
||||
// warn!("Retrying copy...");
|
||||
//
|
||||
// rename_across_devices(&temp_path, &args.final_filesystem_file_path)
|
||||
// .map_err(|err| {
|
||||
// error!("could not rename on disk: {:?}", err);
|
||||
// safe_delete_temp_file(&temp_path);
|
||||
// safe_delete_temp_directory(&temp_dir);
|
||||
// match err {
|
||||
// RenameError::StorageFull => ProcessSingleJobError::FilesystemFull,
|
||||
// RenameError::IoError(err) => ProcessSingleJobError::from_io_error(err),
|
||||
// }
|
||||
// })?;
|
||||
//
|
||||
// let copied_size = file_size(&args.final_filesystem_file_path)
|
||||
// .map_err(|err| ProcessSingleJobError::from_anyhow_error(err))?;
|
||||
//
|
||||
// warn!("Last copy attempt. Final copied size of {} file {:?} is {copied_size}.",
|
||||
// args.name_or_description_of_file, &args.final_filesystem_file_path);
|
||||
//
|
||||
// Ok(())
|
||||
// }
|
||||
//
|
||||
//
|
||||
// pub fn copy_with_logging<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> AnyhowResult<bool> {
|
||||
// let original_size = file_size(&from)?;
|
||||
//
|
||||
// let num_bytes_copied = std::fs::copy(&from, &to)?;
|
||||
//
|
||||
// let destination_size = file_size(&to)?;
|
||||
//
|
||||
// info!(r#"Copied {:?} to {:?}
|
||||
// - Copied bytes: {num_bytes_copied}
|
||||
// - Orig. bytes: {original_size}
|
||||
// - Dest. bytes: {destination_size}
|
||||
// "#, from.as_ref(), to.as_ref());
|
||||
//
|
||||
// let file_sizes_match = original_size == destination_size;
|
||||
//
|
||||
// Ok(file_sizes_match)
|
||||
// }
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
pub mod common_commands;
|
||||
pub mod file_cache_dir;
|
||||
pub mod from_env;
|
||||
pub mod maybe_download_file_from_bucket;
|
||||
#[macro_use]
|
||||
|
||||
@@ -5,12 +5,12 @@ use async_trait::async_trait;
|
||||
use log::{error, info};
|
||||
|
||||
use cloud_storage::bucket_client::BucketClient;
|
||||
use container_common::filesystem::safe_delete_temp_directory::safe_delete_temp_directory;
|
||||
use errors::AnyhowResult;
|
||||
use filesys::create_dir_all_if_missing::create_dir_all_if_missing;
|
||||
use filesys::file_exists::file_exists;
|
||||
use filesys::rename_across_devices::rename_across_devices;
|
||||
use filesys::rename_across_devices::{rename_across_devices, RenameError};
|
||||
use filesys::safe_delete_temp_directory::safe_delete_temp_directory;
|
||||
|
||||
use crate::job::job_loop::process_single_job_error::ProcessSingleJobError;
|
||||
use crate::util::scoped_temp_dir_creator::ScopedTempDirCreator;
|
||||
|
||||
/// Helper utility for downloading pretrained models from GCS.
|
||||
@@ -31,7 +31,7 @@ pub trait ModelDownloader {
|
||||
&self,
|
||||
bucket_client: &BucketClient,
|
||||
scoped_tempdir_creator: &ScopedTempDirCreator,
|
||||
) -> AnyhowResult<()> {
|
||||
) -> Result<(), ProcessSingleJobError> {
|
||||
let filesystem_path = self.get_filesystem_path();
|
||||
|
||||
if file_exists(filesystem_path) {
|
||||
@@ -71,10 +71,13 @@ pub trait ModelDownloader {
|
||||
info!("Renaming {} file from {:?} to {:?}!", model_name, &temp_path, filesystem_path);
|
||||
|
||||
rename_across_devices(&temp_path, filesystem_path)
|
||||
.map_err(|e| {
|
||||
error!("could not rename on disk: {:?}", e);
|
||||
.map_err(|err| {
|
||||
error!("could not rename on disk: {:?}", err);
|
||||
safe_delete_temp_directory(&temp_dir);
|
||||
anyhow!("couldn't rename disk files: {:?}", e)
|
||||
match err {
|
||||
RenameError::StorageFull => ProcessSingleJobError::FilesystemFull,
|
||||
RenameError::IoError(err) => ProcessSingleJobError::from_io_error(err),
|
||||
}
|
||||
})?;
|
||||
|
||||
info!("Finished downloading {} file to {:?}", model_name, filesystem_path);
|
||||
|
||||
@@ -15,7 +15,11 @@ impl ScopedTempDirCreator {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_base_dir(&self) -> &Path {
|
||||
&self.base_dir
|
||||
}
|
||||
|
||||
pub fn new_tempdir(&self, name: &str) -> std::io::Result<TempDir> {
|
||||
TempDir::new_in(&self.base_dir, name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user