mirror of
https://github.com/storytold/artcraft.git
synced 2026-10-28 04:22:51 -04:00
Compare commits
30
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cecd3dd6df | ||
|
|
7b90b11ce6 | ||
|
|
fc154c4a31 | ||
|
|
24818f8ecf | ||
|
|
2d91504eb5 | ||
|
|
67a8bb739b | ||
|
|
eebedbce07 | ||
|
|
f4497a4aee | ||
|
|
447a457dff | ||
|
|
7f65014d6d | ||
|
|
c4681937b3 | ||
|
|
2d52ac0fa9 | ||
|
|
8709fa9c8a | ||
|
|
4250469fd3 | ||
|
|
e5ed4d986f | ||
|
|
ea84b009a8 | ||
|
|
aa202172a2 | ||
|
|
1b4e3cccb5 | ||
|
|
796e8b5aee | ||
|
|
1614cba2f8 | ||
|
|
dbe989c5a1 | ||
|
|
a2cad0b289 | ||
|
|
74db1683b1 | ||
|
|
6e5e326d0e | ||
|
|
bcd806e7f0 | ||
|
|
20b95c090e | ||
|
|
87b2f4a113 | ||
|
|
a7799be70e | ||
|
|
7d858d2c19 | ||
|
|
733c24aebb |
Generated
+1
@@ -3078,6 +3078,7 @@ dependencies = [
|
||||
"enums",
|
||||
"errors",
|
||||
"filesys",
|
||||
"google_drive_common",
|
||||
"hashing",
|
||||
"hostname",
|
||||
"hyper",
|
||||
|
||||
@@ -29,6 +29,8 @@ pub enum InferenceCategory {
|
||||
#[serde(rename = "video_filter")]
|
||||
VideoFilter,
|
||||
|
||||
#[serde(rename = "image_generation")]
|
||||
ImageGeneration,
|
||||
#[serde(rename = "mocap")]
|
||||
Mocap,
|
||||
}
|
||||
@@ -45,6 +47,7 @@ impl InferenceCategory {
|
||||
Self::TextToSpeech => "text_to_speech",
|
||||
Self::VoiceConversion => "voice_conversion",
|
||||
Self::VideoFilter => "video_filter",
|
||||
Self::ImageGeneration => "image_generation",
|
||||
Self::Mocap => "mocap",
|
||||
}
|
||||
}
|
||||
@@ -55,6 +58,7 @@ impl InferenceCategory {
|
||||
"text_to_speech" => Ok(Self::TextToSpeech),
|
||||
"voice_conversion" => Ok(Self::VoiceConversion),
|
||||
"video_filter" => Ok(Self::VideoFilter),
|
||||
"image_generation" => Ok(Self::ImageGeneration),
|
||||
"mocap" => Ok(Self::Mocap),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
@@ -68,6 +72,7 @@ impl InferenceCategory {
|
||||
Self::TextToSpeech,
|
||||
Self::VoiceConversion,
|
||||
Self::VideoFilter,
|
||||
Self::ImageGeneration,
|
||||
Self::Mocap,
|
||||
])
|
||||
}
|
||||
@@ -84,6 +89,7 @@ mod tests {
|
||||
assert_serialization(InferenceCategory::TextToSpeech, "text_to_speech");
|
||||
assert_serialization(InferenceCategory::VoiceConversion, "voice_conversion");
|
||||
assert_serialization(InferenceCategory::VideoFilter, "video_filter");
|
||||
assert_serialization(InferenceCategory::ImageGeneration, "image_generation");
|
||||
assert_serialization(InferenceCategory::Mocap, "mocap")
|
||||
}
|
||||
|
||||
@@ -93,6 +99,7 @@ mod tests {
|
||||
assert_eq!(InferenceCategory::TextToSpeech.to_str(), "text_to_speech");
|
||||
assert_eq!(InferenceCategory::VoiceConversion.to_str(), "voice_conversion");
|
||||
assert_eq!(InferenceCategory::VideoFilter.to_str(), "video_filter");
|
||||
assert_eq!(InferenceCategory::ImageGeneration.to_str(), "image_generation");
|
||||
assert_eq!(InferenceCategory::Mocap.to_str(), "mocap");
|
||||
}
|
||||
|
||||
@@ -102,6 +109,7 @@ mod tests {
|
||||
assert_eq!(InferenceCategory::from_str("text_to_speech").unwrap(), InferenceCategory::TextToSpeech);
|
||||
assert_eq!(InferenceCategory::from_str("voice_conversion").unwrap(), InferenceCategory::VoiceConversion);
|
||||
assert_eq!(InferenceCategory::from_str("video_filter").unwrap(), InferenceCategory::VideoFilter);
|
||||
assert_eq!(InferenceCategory::from_str("image_generation").unwrap(), InferenceCategory::ImageGeneration);
|
||||
assert_eq!(InferenceCategory::from_str("mocap").unwrap(), InferenceCategory::Mocap);
|
||||
}
|
||||
|
||||
@@ -114,6 +122,7 @@ mod tests {
|
||||
assert_eq!(variants.pop_first(), Some(InferenceCategory::TextToSpeech));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceCategory::VoiceConversion));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceCategory::VideoFilter));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceCategory::ImageGeneration));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceCategory::Mocap));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
|
||||
|
||||
@@ -33,6 +33,8 @@ pub enum InferenceModelType {
|
||||
VallEX,
|
||||
#[serde(rename = "rerender_a_video")]
|
||||
RerenderAVideo,
|
||||
#[serde(rename = "stable_diffusion")]
|
||||
StableDiffusion,
|
||||
#[serde(rename = "mocap_net")]
|
||||
MocapNet,
|
||||
#[serde(rename = "styletts2")]
|
||||
@@ -54,6 +56,7 @@ impl InferenceModelType {
|
||||
Self::Vits => "vits",
|
||||
Self::VallEX => "vall_e_x",
|
||||
Self::RerenderAVideo => "rerender_a_video",
|
||||
Self::StableDiffusion => "stable_diffusion",
|
||||
Self::MocapNet => "mocap_net",
|
||||
Self::StyleTTS2 => "styletts2",
|
||||
}
|
||||
@@ -68,6 +71,7 @@ impl InferenceModelType {
|
||||
"vits" => Ok(Self::Vits),
|
||||
"vall_e_x" => Ok(Self::VallEX),
|
||||
"rerender_a_video" => Ok(Self::RerenderAVideo),
|
||||
"stable_diffusion" => Ok(Self::StableDiffusion),
|
||||
"mocap_net" => Ok(Self::MocapNet),
|
||||
"styletts2" => Ok(Self::StyleTTS2),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
@@ -85,6 +89,7 @@ impl InferenceModelType {
|
||||
InferenceModelType::Vits,
|
||||
InferenceModelType::VallEX,
|
||||
InferenceModelType::RerenderAVideo,
|
||||
InferenceModelType::StableDiffusion,
|
||||
InferenceModelType::MocapNet,
|
||||
InferenceModelType::StyleTTS2,
|
||||
])
|
||||
@@ -105,6 +110,7 @@ mod tests {
|
||||
assert_serialization(InferenceModelType::Vits, "vits");
|
||||
assert_serialization(InferenceModelType::VallEX, "vall_e_x");
|
||||
assert_serialization(InferenceModelType::RerenderAVideo, "rerender_a_video");
|
||||
assert_serialization(InferenceModelType::StableDiffusion, "stable_diffusion");
|
||||
assert_serialization(InferenceModelType::MocapNet, "mocap_net");
|
||||
assert_serialization(InferenceModelType::StyleTTS2, "styletts2");
|
||||
}
|
||||
@@ -118,6 +124,7 @@ mod tests {
|
||||
assert_eq!(InferenceModelType::Vits.to_str(), "vits");
|
||||
assert_eq!(InferenceModelType::VallEX.to_str(), "vall_e_x");
|
||||
assert_eq!(InferenceModelType::RerenderAVideo.to_str(), "rerender_a_video");
|
||||
assert_eq!(InferenceModelType::StableDiffusion.to_str(), "stable_diffusion");
|
||||
assert_eq!(InferenceModelType::MocapNet.to_str(), "mocap_net");
|
||||
assert_eq!(InferenceModelType::StyleTTS2.to_str(), "styletts2");
|
||||
}
|
||||
@@ -131,6 +138,7 @@ mod tests {
|
||||
assert_eq!(InferenceModelType::from_str("vits").unwrap(), InferenceModelType::Vits);
|
||||
assert_eq!(InferenceModelType::from_str("vall_e_x").unwrap(), InferenceModelType::VallEX);
|
||||
assert_eq!(InferenceModelType::from_str("rerender_a_video").unwrap(), InferenceModelType::RerenderAVideo);
|
||||
assert_eq!(InferenceModelType::from_str("stable_diffusion").unwrap(), InferenceModelType::StableDiffusion);
|
||||
assert_eq!(InferenceModelType::from_str("mocap_net").unwrap(), InferenceModelType::MocapNet);
|
||||
assert_eq!(InferenceModelType::from_str("styletts2").unwrap(), InferenceModelType::StyleTTS2);
|
||||
}
|
||||
@@ -139,6 +147,7 @@ mod tests {
|
||||
fn all_variants() {
|
||||
// Static check
|
||||
let mut variants = InferenceModelType::all_variants();
|
||||
assert_eq!(variants.len(), 8);
|
||||
assert_eq!(variants.len(), 9);
|
||||
assert_eq!(variants.pop_first(), Some(InferenceModelType::RvcV2));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceModelType::SadTalker));
|
||||
@@ -147,6 +156,7 @@ mod tests {
|
||||
assert_eq!(variants.pop_first(), Some(InferenceModelType::Vits));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceModelType::VallEX));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceModelType::RerenderAVideo));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceModelType::StableDiffusion));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceModelType::MocapNet));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceModelType::StyleTTS2));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
|
||||
@@ -29,6 +29,9 @@ pub enum InferenceResultType {
|
||||
|
||||
#[serde(rename = "zs_voice_embedding")]
|
||||
ZeroShotVoiceEmbedding,
|
||||
|
||||
#[serde(rename = "upload_model")]
|
||||
UploadModel
|
||||
}
|
||||
|
||||
// TODO(bt, 2022-12-21): This desperately needs MySQL integration tests!
|
||||
@@ -43,6 +46,7 @@ impl InferenceResultType {
|
||||
Self::TextToSpeech => "text_to_speech",
|
||||
Self::VoiceConversion => "voice_conversion",
|
||||
Self::ZeroShotVoiceEmbedding => "zs_voice_embedding",
|
||||
Self::UploadModel => "upload_model",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,6 +56,7 @@ impl InferenceResultType {
|
||||
"text_to_speech" => Ok(Self::TextToSpeech),
|
||||
"voice_conversion" => Ok(Self::VoiceConversion),
|
||||
"zs_voice_embedding" => Ok(Self::ZeroShotVoiceEmbedding),
|
||||
"upload_model" => Ok(Self::UploadModel),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
@@ -64,6 +69,7 @@ impl InferenceResultType {
|
||||
InferenceResultType::TextToSpeech,
|
||||
InferenceResultType::VoiceConversion,
|
||||
InferenceResultType::ZeroShotVoiceEmbedding,
|
||||
InferenceResultType::UploadModel,
|
||||
])
|
||||
}
|
||||
}
|
||||
@@ -79,6 +85,7 @@ mod tests {
|
||||
assert_serialization(InferenceResultType::TextToSpeech, "text_to_speech");
|
||||
assert_serialization(InferenceResultType::VoiceConversion, "voice_conversion");
|
||||
assert_serialization(InferenceResultType::ZeroShotVoiceEmbedding, "zs_voice_embedding");
|
||||
assert_serialization(InferenceResultType::UploadModel, "upload_model");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -87,6 +94,7 @@ mod tests {
|
||||
assert_eq!(InferenceResultType::TextToSpeech.to_str(), "text_to_speech");
|
||||
assert_eq!(InferenceResultType::VoiceConversion.to_str(), "voice_conversion");
|
||||
assert_eq!(InferenceResultType::ZeroShotVoiceEmbedding.to_str(), "zs_voice_embedding");
|
||||
assert_eq!(InferenceResultType::UploadModel.to_str(), "upload_model");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -95,6 +103,7 @@ mod tests {
|
||||
assert_eq!(InferenceResultType::from_str("text_to_speech").unwrap(), InferenceResultType::TextToSpeech);
|
||||
assert_eq!(InferenceResultType::from_str("voice_conversion").unwrap(), InferenceResultType::VoiceConversion);
|
||||
assert_eq!(InferenceResultType::from_str("zs_voice_embedding").unwrap(), InferenceResultType::ZeroShotVoiceEmbedding);
|
||||
assert_eq!(InferenceResultType::from_str("upload_model").unwrap(), InferenceResultType::UploadModel);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -106,6 +115,7 @@ mod tests {
|
||||
assert_eq!(variants.pop_first(), Some(InferenceResultType::TextToSpeech));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceResultType::VoiceConversion));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceResultType::ZeroShotVoiceEmbedding));
|
||||
assert_eq!(variants.pop_first(), Some(InferenceResultType::UploadModel));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
|
||||
// Generated check
|
||||
|
||||
@@ -10,6 +10,7 @@ use crate::cli_args::parse_cli_args;
|
||||
use crate::seeding::model_weights::seed_weights; // V1
|
||||
use crate::seeding::seed_media_files::seed_media_files;
|
||||
use crate::seeding::seed_model_weights::seed_weights_files; // V2 v3 will come later on when everything is more conslidated and clear.
|
||||
use crate::seeding::model_weights::test_seed_weights_files;
|
||||
use crate::seeding::tts_tacotron2::seed_tts_tacotron2;
|
||||
use crate::seeding::users::seed_user_accounts;
|
||||
use crate::seeding::voice_conversion::seed_voice_conversion;
|
||||
@@ -60,9 +61,10 @@ pub async fn main() -> AnyhowResult<()> {
|
||||
seed_tts_tacotron2(&pool, maybe_bucket_clients.as_ref()).await?;
|
||||
|
||||
// should seed the weights with a few files for hanashi
|
||||
seed_weights_files(&pool, maybe_bucket_clients.as_ref()).await?;
|
||||
|
||||
info!("Done!");
|
||||
//seed_weights_files(&pool, maybe_bucket_clients.as_ref()).await?;
|
||||
//println!("TESTING DOWLOAD");
|
||||
//test_seed_weights_files().await?;
|
||||
//info!("Done!");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
use std::path::PathBuf;
|
||||
use std::vec;
|
||||
|
||||
use log::info;
|
||||
use sqlx::{MySql, Pool};
|
||||
use cloud_storage::remote_file_manager::remote_cloud_file_manager::RemoteCloudFileClient;
|
||||
use cloud_storage::remote_file_manager::remote_cloud_bucket_details::RemoteCloudBucketDetails;
|
||||
|
||||
use cloud_storage::remote_file_manager::weights_descriptor;
|
||||
use cloud_storage::remote_file_manager::weights_descriptor::{WeightsLoRADescriptor, WeightsSD15Descriptor};
|
||||
use easyenv::from_filename;
|
||||
|
||||
use enums::by_table::model_weights::{
|
||||
weights_category::WeightsCategory,
|
||||
@@ -10,12 +17,50 @@ use enums::by_table::model_weights::{
|
||||
use enums::common::visibility::Visibility;
|
||||
use errors::{anyhow, AnyhowResult};
|
||||
use mysql_queries::queries::model_weights::create::create_weight::{create_weight, CreateModelWeightsArgs};
|
||||
use mysql_queries::queries::users::user::create_account::create_account;
|
||||
use mysql_queries::queries::users::user::get_user_token_by_username::get_user_token_by_username;
|
||||
use storyteller_root::get_seed_tool_data_root;
|
||||
use tokens::tokens::model_weights::ModelWeightToken;
|
||||
use tokens::tokens::users::UserToken;
|
||||
|
||||
use crate::seeding::users::HANASHI_USERNAME;
|
||||
|
||||
pub async fn test_seed_weights_files() -> AnyhowResult<()> {
|
||||
|
||||
let seed_path = PathBuf::from("/storyteller/root/custom-seed-tool-data");
|
||||
let remote_cloud_file_client = RemoteCloudFileClient::get_remote_cloud_file_client().await;
|
||||
let remote_cloud_file_client = match remote_cloud_file_client {
|
||||
Ok(res) => {
|
||||
res
|
||||
}
|
||||
Err(_) => {
|
||||
return Err(anyhow!("failed to get remote cloud file client"));
|
||||
}
|
||||
};
|
||||
|
||||
let mut path_dl1 = seed_path.clone();
|
||||
path_dl1.push("downloads/loRA");
|
||||
let mut path_dl2 = seed_path.clone();
|
||||
path_dl2.push("downloads/checkpoint");
|
||||
|
||||
let bucket_details1 = RemoteCloudBucketDetails {
|
||||
object_hash: String::from("apa0ej6es8d3ss2gwtf1cghge35qn9tn"),
|
||||
prefix: String::from("sd15"),
|
||||
suffix: String::from("safetensors"),
|
||||
};
|
||||
|
||||
let bucket_details2 = RemoteCloudBucketDetails {
|
||||
object_hash: String::from("27kz11et18fargyyxbj66ntfn621k9d3"),
|
||||
prefix: String::from("loRA"),
|
||||
suffix: String::from("safetensors"),
|
||||
};
|
||||
|
||||
remote_cloud_file_client.download_file(bucket_details1, String::from("./checkpoint")).await?;
|
||||
remote_cloud_file_client.download_file(bucket_details2, String::from("./loRA")).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn seed_weights_for_paging(mysql_pool: &Pool<MySql>, user_token: UserToken) -> AnyhowResult<()> {
|
||||
let sd1_5_markdown_description = r#"
|
||||
# Dragonfruit AI Models Update and Workflow
|
||||
@@ -330,6 +375,328 @@ pub async fn seed_weights_for_paging(mysql_pool: &Pool<MySql>, user_token: UserT
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn seed_weights_for_testing_inference(mysql_pool: &Pool<MySql>, user_token: UserToken) -> AnyhowResult<()>{
|
||||
|
||||
|
||||
let miyhoyo_description = r#"一个面向米哈游角色的模型合集~A collection for MIHOYO Characters~
|
||||
对应人物tag记录在版本信息里,可在右侧“About this version”选项中查看。The corresponding character prompts are recorded in the version information and can be viewed in the About this version option on the right.
|
||||
打开目录寻找最爱~(附带链接,点击直达)~Open the catalog, find your favorites~ (with links, click to go directly):
|
||||
崩坏三 Honkai Impact 3rd:
|
||||
|
||||
梅比乌斯- Mobius
|
||||
|
||||
琪亚娜-Kiana:琪亚娜 合集-Collections for Kiana (Honkai Impact 3rd)
|
||||
|
||||
布洛妮娅-bronya:布洛妮娅 合集-Collections for Bronya (Honkai Impact 3rd | Honkai Star Rail)
|
||||
|
||||
芽衣:雷电芽衣 合集-Collections for Raiden Mei (Honkai Impact 3rd)
|
||||
|
||||
西琳-Sirin
|
||||
|
||||
魔法少女-Miracle ☆ Magical Girl
|
||||
|
||||
赤鸢-Jingwei
|
||||
|
||||
丹朱苍玄-Nuwa/Fuxi
|
||||
|
||||
李素裳-Li Sushang
|
||||
|
||||
玉骑士·月痕/锦岁玉团-Jade Knight/Auspicious Dazzle
|
||||
|
||||
卡莲-kallen
|
||||
|
||||
第六夜想曲-Sixth Serenade
|
||||
|
||||
符华-Fu hua
|
||||
|
||||
崩落
|
||||
|
||||
云墨丹心-Azure Empyrea
|
||||
|
||||
八重樱-Yae Sakura
|
||||
|
||||
逆神巫女-Gyakushinn Miko
|
||||
|
||||
御神装·勿忘-Goushinnso Memento
|
||||
|
||||
信花舞伎-Blooming Maiko
|
||||
|
||||
希尔-Seele
|
||||
|
||||
生死律者-Herrscher of Rebirth
|
||||
|
||||
栖于永夜-Eternal Night's Embrace
|
||||
|
||||
德莉莎-Theresa:德莉莎 合集-Collections for Theresa (Honkai Impact 3rd)
|
||||
|
||||
月下誓约-Lunar Vow: Crimson Love
|
||||
|
||||
月下初拥-Luna Kindred
|
||||
|
||||
花裳月纱-Rosy Bridesmaid
|
||||
|
||||
格蕾修-Griseo
|
||||
|
||||
繁星·绘世之卷-Starry Impression
|
||||
|
||||
天行·绘星之卷-Cosmic Expression
|
||||
|
||||
画中的童话-Maroon Riding Hood
|
||||
|
||||
原神 Genshin:
|
||||
|
||||
凝光-Ningguang
|
||||
|
||||
申鹤-Shenhe
|
||||
|
||||
妮露
|
||||
|
||||
诺艾尔
|
||||
|
||||
神里绫华(包含礼装)
|
||||
|
||||
甘雨(包含喜茶联动礼装)-Ganyu
|
||||
|
||||
胡桃(包含森罗联动礼装)-Hutao
|
||||
|
||||
琳妮特-Lynette
|
||||
|
||||
绮良良-Kirara
|
||||
|
||||
坎蒂丝-Candace
|
||||
|
||||
芙宁娜-Furina
|
||||
|
||||
芙宁娜/芙卡洛斯-Furina/Focalors
|
||||
|
||||
克洛琳德-Clorinde
|
||||
|
||||
娜维娅-Navia
|
||||
|
||||
丝柯克-Skirk
|
||||
|
||||
夏洛蒂-Charlotte
|
||||
|
||||
归终-Guizhong
|
||||
|
||||
闲云-Xianyun
|
||||
|
||||
千织-Chiori
|
||||
|
||||
夏沃蕾-Chevreuse
|
||||
|
||||
崩坏:星穹铁道 Honkai Star Rand:
|
||||
|
||||
驭空-Yukong
|
||||
|
||||
银狼-Silver Wolf
|
||||
|
||||
符玄-Fu Xuan
|
||||
|
||||
李素裳-Sushang
|
||||
|
||||
三月七(礼装)-March 7th (New Outfit)
|
||||
|
||||
停云-Tingyun
|
||||
|
||||
青雀-Qingque
|
||||
|
||||
布洛妮娅·兰德-Bronya Rand
|
||||
|
||||
镜流-Jingliu
|
||||
|
||||
卡芙卡-Kafka
|
||||
|
||||
托帕-Topaz
|
||||
|
||||
桂乃芬-Guinaifen
|
||||
|
||||
玲可-Lynx
|
||||
|
||||
佩拉-Peia
|
||||
|
||||
寒鸦-Hanya
|
||||
|
||||
藿藿-Huohuo
|
||||
|
||||
阮·梅-Ruan Mei
|
||||
|
||||
雪衣-Xueyi
|
||||
|
||||
希露瓦-Serval
|
||||
|
||||
绝区零 Zenless-zone-zero:
|
||||
|
||||
星见雅-Miyabi
|
||||
|
||||
猫宫又奈-Nekomata
|
||||
|
||||
艾莲·乔-Ellen
|
||||
|
||||
妮可-Nicole
|
||||
|
||||
苍角-Soukaku
|
||||
|
||||
格莉丝-Grace
|
||||
|
||||
珂蕾妲-koleda
|
||||
|
||||
可琳-Corin
|
||||
|
||||
其他 Others:
|
||||
|
||||
鹿鸣-Luming
|
||||
"""#;
|
||||
|
||||
let sd1_5_markdown_description = r#"
|
||||
00025-2161235528-1girl,(orange_hair_1.1),(zentangle, mandala, tangle, entangle_0.6),(fractal art),the most beautiful form of chaos,brutalist desi.png
|
||||
|
||||
|
||||
00010-1626070972-elf portrait,enchanting beauty,fantasy,ethereal glow,pointed ears,delicate facial features,long elegant hair,nature-themed attir.png
|
||||
|
||||
|
||||
00001-301370162-girl in a snowy landscape,winter coat,fluffy hood,white fur trim,breath visible in cold air,soft falling snowflakes,glistening s.png
|
||||
|
||||
|
||||
00002-3996269517-venomous sorcerer,ominous dark robes,glowing green eyes,holding a staff with a serpent design,mystical green flames,poisonous mi.png
|
||||
|
||||
|
||||
00003-3817469732-Thunder Deity,immense power,hovering above the sea,stormy ocean waves below,crackling lightning in fingertips,dramatic stormy cl.png
|
||||
|
||||
if you want to remake my front image, check this out: Lightflow | SD webUI Extension - workflow restore & save in one click - majicMIXfantasy example | Stable Diffusion Other | Civitai
|
||||
|
||||
v3 is here. Shouldn't be difficult to use. Simple and complex prompts can be used, unleash your imagination.
|
||||
|
||||
v3来了,简单复杂的提示词都可以用。
|
||||
|
||||
I developed the v3 version towards 2D in order to make more room for 2.5D models like majicmix lux.
|
||||
|
||||
v3版本我往2D发展是为了给majicmix lux等2.5D模型让出更多空间。
|
||||
|
||||
merged from融了:
|
||||
Jack Of All by GeneratedJudge
|
||||
|
||||
AWPainting by DynamicWang
|
||||
|
||||
majicMIX fantasy v2 =
|
||||
Noosphere by skumerz + dalcefoPainting + 饭特稀V08 by zhazhahui345 + GhostMix
|
||||
"#;
|
||||
|
||||
|
||||
let sd_vae_description = r"This is an earlier version of a stable VAE. Compared to other VAEs, it has a higher level of stability. I am not the creator, but I could not find this VAE on the website, so I am sharing it here.
|
||||
这是较早时候的稳定VAE,与其他VAE相比具有较高的稳定性,不容易坏图。我不是作者,但是站里没找着所以搬运。#";
|
||||
|
||||
|
||||
info!("Seeding weights for inference...");
|
||||
ModelWeightToken::reset_rng_for_testing_and_dev_seeding_never_use_in_production_seriously(54321);
|
||||
let model_weight_token1 = ModelWeightToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously();
|
||||
let model_weight_token2 = ModelWeightToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously();
|
||||
let model_weight_token3 = ModelWeightToken::generate_for_testing_and_dev_seeding_never_use_in_production_seriously();
|
||||
|
||||
|
||||
let remote_cloud_file_client = RemoteCloudFileClient::get_remote_cloud_file_client().await?;
|
||||
|
||||
let sd_15_weights_descriptor = Box::new(WeightsSD15Descriptor {});
|
||||
let lora_descriptor = Box::new(WeightsLoRADescriptor{});
|
||||
let sd_vae_15_weights_descriptor = Box::new(WeightsSD15Descriptor {});
|
||||
let mut path_object_SD = get_seed_tool_data_root();
|
||||
path_object_SD.push("models/imagegen/sd15/majicmixFantasy_v30Vae.safetensors");
|
||||
|
||||
let mut path_object_loRA = get_seed_tool_data_root();
|
||||
path_object_loRA.push("models/imagegen/loRA/xiawolei-v100-000019.safetensors");
|
||||
|
||||
let mut path_to_VAE = get_seed_tool_data_root();
|
||||
path_to_VAE.push("models/imagegen/vae/zVae_v20.safetensors");
|
||||
|
||||
let metadata1 = remote_cloud_file_client.upload_file(sd_15_weights_descriptor,path_object_SD.as_path().to_str().unwrap()).await?;
|
||||
let metadata2 = remote_cloud_file_client.upload_file(lora_descriptor,path_object_loRA.as_path().to_str().unwrap()).await?;
|
||||
let metadata3 = remote_cloud_file_client.upload_file(sd_vae_15_weights_descriptor,path_to_VAE.as_path().to_str().unwrap()).await?;
|
||||
|
||||
let weights1 = CreateModelWeightsArgs {
|
||||
token: &model_weight_token1, // replace with actual ModelWeightToken
|
||||
weights_type: WeightsType::StableDiffusion15, // replace with actual WeightsType
|
||||
weights_category: WeightsCategory::ImageGeneration, // replace with actual WeightsCategory
|
||||
title: "Dragonfruit".to_string(),
|
||||
maybe_description_markdown: Some(sd1_5_markdown_description.to_string()),
|
||||
maybe_description_rendered_html: Some("<p>Description</p>".to_string()),
|
||||
creator_user_token: Some(&user_token), // replace with actual UserToken
|
||||
creator_ip_address: "192.168.1.1",
|
||||
creator_set_visibility: Visibility::Public,
|
||||
maybe_last_update_user_token: Some("Last Update User Token".to_string()),
|
||||
original_download_url: Some("https://civitai.com/models/41865/majicmix-fantasy".to_string()),
|
||||
original_filename: Some("majicmixFantasy_v30Vae.safetensors".to_string()),
|
||||
file_size_bytes: metadata1.file_size_bytes as i32,
|
||||
file_checksum_sha2: metadata1.sha256_checksum.to_string(),
|
||||
public_bucket_hash: metadata1.bucket_details.clone().unwrap().object_hash,
|
||||
maybe_public_bucket_prefix: Some(metadata1.bucket_details.clone().unwrap().prefix),
|
||||
maybe_public_bucket_extension: Some(metadata1.bucket_details.clone().unwrap().suffix),
|
||||
cached_user_ratings_total_count: 10,
|
||||
cached_user_ratings_positive_count: 9,
|
||||
cached_user_ratings_negative_count: 1,
|
||||
maybe_cached_user_ratings_ratio: Some(0.9),
|
||||
version: 1,
|
||||
mysql_pool: &mysql_pool, // replace with actual MySqlPool
|
||||
};
|
||||
|
||||
let weights2 = CreateModelWeightsArgs {
|
||||
token: &model_weight_token2, // replace with actual ModelWeightToken
|
||||
weights_type: WeightsType::LoRA, // replace with actual WeightsType
|
||||
weights_category: WeightsCategory::ImageGeneration, // replace with actual WeightsCategory
|
||||
title: "MIHOYO Collection 米家全家桶 (Honkai Impact 3rd | Honkai Star Rail | Genshin Impact | Zenless Zone Zero)".to_string(),
|
||||
maybe_description_markdown: Some(miyhoyo_description.to_string()),
|
||||
maybe_description_rendered_html: Some(miyhoyo_description.to_string()),
|
||||
creator_user_token: Some(&user_token), // replace with actual UserToken
|
||||
creator_ip_address: "292.268.2.2",
|
||||
creator_set_visibility: Visibility::Public,
|
||||
maybe_last_update_user_token: Some("<p> Honkai <p>".to_string()),
|
||||
original_download_url: Some("https://civitai.com/models/95243/mihoyo-collection-honkai-impact-3rd-or-honkai-star-rail-or-genshin-impact-or-zenless-zone-zero".to_string()),
|
||||
original_filename: Some("xiawolei-v100-000019.safetensors".to_string()),
|
||||
file_size_bytes: metadata2.file_size_bytes as i32,
|
||||
file_checksum_sha2: metadata2.sha256_checksum.to_string(),
|
||||
public_bucket_hash: metadata2.bucket_details.clone().unwrap().object_hash.clone(),
|
||||
maybe_public_bucket_prefix: Some(metadata2.bucket_details.clone().unwrap().prefix),
|
||||
maybe_public_bucket_extension: Some(metadata2.bucket_details.clone().unwrap().suffix),
|
||||
cached_user_ratings_total_count: 20,
|
||||
cached_user_ratings_positive_count: 9,
|
||||
cached_user_ratings_negative_count: 2,
|
||||
maybe_cached_user_ratings_ratio: Some(0.9),
|
||||
version: 2,
|
||||
mysql_pool: &mysql_pool, // replace with actual MySqlPool
|
||||
};
|
||||
|
||||
let weights3 = CreateModelWeightsArgs {
|
||||
token: &model_weight_token3, // replace with actual ModelWeightToken
|
||||
weights_type: WeightsType::StableDiffusion15, // replace with actual WeightsType
|
||||
weights_category: WeightsCategory::ImageGeneration, // replace with actual WeightsCategory
|
||||
title: "z-vae".to_string(),
|
||||
maybe_description_markdown: Some(sd_vae_description.to_string()),
|
||||
maybe_description_rendered_html: Some("<p>Description</p>".to_string()),
|
||||
creator_user_token: Some(&user_token), // replace with actual UserToken
|
||||
creator_ip_address: "192.168.1.1",
|
||||
creator_set_visibility: Visibility::Public,
|
||||
maybe_last_update_user_token: Some("Last Update User Token".to_string()),
|
||||
original_download_url: Some("https://civitai.com/models/97653/z-vae".to_string()),
|
||||
original_filename: Some("zVae_v20.safetensors".to_string()),
|
||||
file_size_bytes: metadata3.file_size_bytes as i32,
|
||||
file_checksum_sha2: metadata3.sha256_checksum.to_string(),
|
||||
public_bucket_hash: metadata3.bucket_details.clone().unwrap().object_hash,
|
||||
maybe_public_bucket_prefix: Some(metadata3.bucket_details.clone().unwrap().prefix),
|
||||
maybe_public_bucket_extension: Some(metadata3.bucket_details.clone().unwrap().suffix),
|
||||
cached_user_ratings_total_count: 10,
|
||||
cached_user_ratings_positive_count: 9,
|
||||
cached_user_ratings_negative_count: 1,
|
||||
maybe_cached_user_ratings_ratio: Some(0.9),
|
||||
version: 1,
|
||||
mysql_pool: &mysql_pool, // replace with actual MySqlPool
|
||||
};
|
||||
|
||||
create_weight(weights1).await?;
|
||||
create_weight(weights2).await?;
|
||||
create_weight(weights3).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
pub async fn seed_weights_for_user_token(
|
||||
mysql_pool: &Pool<MySql>,
|
||||
user_token: UserToken
|
||||
@@ -630,6 +997,7 @@ pub async fn original_seed_weights(mysql_pool: &Pool<MySql>, _user_token: UserTo
|
||||
Ok(())
|
||||
|
||||
}
|
||||
|
||||
pub async fn seed_weights(mysql_pool: &Pool<MySql>) -> AnyhowResult<()> {
|
||||
info!("Seeding weights...");
|
||||
|
||||
@@ -642,7 +1010,9 @@ pub async fn seed_weights(mysql_pool: &Pool<MySql>) -> AnyhowResult<()> {
|
||||
|
||||
//original_seed_weights(mysql_pool,user_token).await?;
|
||||
//seed_weights_for_user_token(mysql_pool, user_token).await?;
|
||||
seed_weights_for_paging(mysql_pool,user_token).await?;
|
||||
|
||||
//seed_weights_for_paging(mysql_pool,user_token).await?;
|
||||
seed_weights_for_testing_inference(mysql_pool,user_token).await?;
|
||||
//println!("TESTING DOWLOAD");
|
||||
//test_seed_weights_files().await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -226,3 +226,5 @@ async fn seed_file_to_bucket(
|
||||
maybe_bucket_extension: maybe_bucket_extension.map(|s| s.to_string()),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ pub trait BucketOrchestrationCore {
|
||||
bytes: &[u8],
|
||||
content_type: &str,
|
||||
is_public: bool) -> AnyhowResult<()>;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
use crate::remote_file_manager::remote_cloud_bucket_details::RemoteCloudBucketDetails;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct FileMetaData {
|
||||
pub file_size_bytes: u64,
|
||||
pub sha256_checksum: String,
|
||||
pub mimetype: String
|
||||
pub mimetype: String,
|
||||
pub bucket_details: Option<RemoteCloudBucketDetails>
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
use crate::remote_file_manager::file_descriptor::FileDescriptor;
|
||||
// TODO ASK BRANDON WHAT path should this be?
|
||||
const MEDIA_FILE_DIRECTORY: &str = "/media";
|
||||
|
||||
pub struct MediaImagePngDescriptor {}
|
||||
impl FileDescriptor for MediaImagePngDescriptor {
|
||||
fn remote_directory_path(&self) -> &str {
|
||||
MEDIA_FILE_DIRECTORY
|
||||
}
|
||||
fn get_suffix(&self)->String {
|
||||
"png".to_string()
|
||||
}
|
||||
|
||||
fn get_prefix(&self)->String {
|
||||
"image".to_string()
|
||||
}
|
||||
|
||||
fn is_public(&self) -> bool {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
use crate::remote_file_manager::weights_descriptor::{self};
|
||||
|
||||
use super::file_descriptor::FileDescriptor;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RemoteCloudBucketDetails {
|
||||
pub object_hash: String,
|
||||
pub prefix: String,
|
||||
|
||||
+24
-10
@@ -12,17 +12,13 @@ use crate::remote_file_manager::remote_cloud_bucket_details::RemoteCloudBucketDe
|
||||
use super::file_descriptor::FileDescriptor;
|
||||
use super::file_meta_data::FileMetaData;
|
||||
|
||||
|
||||
pub struct RemoteCloudFileClient {
|
||||
bucket_orchestration_client: Box<dyn BucketOrchestrationCore>
|
||||
}
|
||||
|
||||
impl RemoteCloudFileClient {
|
||||
pub fn new(bucket_orchestration_client: Box<dyn BucketOrchestrationCore>) -> Self {
|
||||
Self {
|
||||
bucket_orchestration_client
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub async fn get_remote_cloud_file_client() -> AnyhowResult<Self> {
|
||||
let bucket_orchestration = match BucketOrchestration::new_bucket_client_from_existing_env() {
|
||||
Ok(client) => client,
|
||||
@@ -36,6 +32,13 @@ impl RemoteCloudFileClient {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn new(bucket_orchestration_client: Box<dyn BucketOrchestrationCore>) -> Self {
|
||||
Self {
|
||||
bucket_orchestration_client
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub async fn download_file(&self, remote_cloud_bucket_details:RemoteCloudBucketDetails, to_system_file_path:String) -> AnyhowResult<()> {
|
||||
let file_descriptor = remote_cloud_bucket_details.file_descriptor_from_bucket_details();
|
||||
let file_bucket_directory = FileBucketDirectory::from_existing_bucket_details(remote_cloud_bucket_details);
|
||||
@@ -53,17 +56,26 @@ impl RemoteCloudFileClient {
|
||||
println!("Reading media file: {:?}", from_system_file_path);
|
||||
// get meta data
|
||||
let bytes = file_read_bytes(from_system_file_path)?;
|
||||
let result = Self::get_file_meta_data(from_system_file_path)?;
|
||||
let mut result = Self::get_file_meta_data(from_system_file_path)?;
|
||||
let is_public = file_descriptor.is_public();
|
||||
|
||||
let suffix = file_descriptor.get_suffix().clone();
|
||||
let prefix = file_descriptor.get_prefix().clone();
|
||||
|
||||
let directory = FileBucketDirectory::generate_new(
|
||||
file_descriptor
|
||||
);
|
||||
|
||||
result.bucket_details = Some(RemoteCloudBucketDetails {
|
||||
object_hash: directory.get_file_object_hash().to_string(),
|
||||
suffix:suffix,
|
||||
prefix:prefix,
|
||||
});
|
||||
|
||||
println!("Uploading media file to bucket path: {:?}",directory.get_full_remote_cloud_file_path());
|
||||
|
||||
self.bucket_orchestration_client.upload_file_with_content_type_process(
|
||||
&directory.get_remote_cloud_base_directory(),
|
||||
&directory.get_full_remote_cloud_file_path(),
|
||||
bytes.as_ref(),
|
||||
result.mimetype.as_ref(),
|
||||
is_public
|
||||
@@ -83,7 +95,8 @@ impl RemoteCloudFileClient {
|
||||
Ok(FileMetaData {
|
||||
file_size_bytes,
|
||||
sha256_checksum,
|
||||
mimetype: mimetype.to_string()
|
||||
mimetype: mimetype.to_string(),
|
||||
bucket_details: None
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -125,7 +138,8 @@ mod tests {
|
||||
is_public: bool) -> AnyhowResult<()> {
|
||||
println!("Upload File to Disk");
|
||||
println!("{}",object_name);
|
||||
assert_eq!(object_name,String::from("/weights/2/y/q/m/2/2yqm2f1bamh88seyd690h9v24apgezhr/loRA_2yqm2f1bamh88seyd690h9v24apgezhr.safetensors"));
|
||||
// this is random you have to just check the outputs
|
||||
//assert_eq!(object_name,String::from("/weights/2/y/q/m/2/2yqm2f1bamh88seyd690h9v24apgezhr/loRA_2yqm2f1bamh88seyd690h9v24apgezhr.safetensors"));
|
||||
println!("ContentType:{}",content_type);
|
||||
println!("{}",is_public);
|
||||
assert_eq!(is_public,true);
|
||||
|
||||
@@ -3,7 +3,6 @@ use super::file_descriptor::FileDescriptor;
|
||||
pub struct WeightsLoRADescriptor;
|
||||
|
||||
const REMOTE_FILE_DIRECTORY: &str = "/weights";
|
||||
|
||||
impl FileDescriptor for WeightsLoRADescriptor {
|
||||
fn remote_directory_path(&self) -> &str {
|
||||
REMOTE_FILE_DIRECTORY
|
||||
@@ -26,6 +25,7 @@ impl FileDescriptor for WeightsLoRADescriptor {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct WeightsSD15Descriptor;
|
||||
|
||||
impl FileDescriptor for WeightsSD15Descriptor {
|
||||
|
||||
@@ -57,6 +57,60 @@ impl GoogleDriveDownloadCommand {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn download_file_with_file_name(&self,
|
||||
download_url: &str,
|
||||
temp_dir: &TempDir,
|
||||
file_name:&str) -> AnyhowResult<String>
|
||||
{
|
||||
let temp_dir_path = temp_dir.path()
|
||||
.to_str()
|
||||
.unwrap_or("/tmp")
|
||||
.to_string();
|
||||
|
||||
let temp_filename = random_crockford_token(10);
|
||||
let temp_filename = format!("{}/{}", temp_dir_path, file_name);
|
||||
|
||||
info!("Downloading {} to: {}", download_url, temp_filename);
|
||||
|
||||
let mut command = format!("{} --url \"{}\" --output_filename {}",
|
||||
&self.download_script,
|
||||
download_url,
|
||||
&temp_filename);
|
||||
|
||||
if let Some(venv_activation_script) = self.maybe_venv_activation_script.as_deref() {
|
||||
// NB: "." is source for non-bash shells
|
||||
command = format!(". {} && {}",
|
||||
venv_activation_script,
|
||||
&command);
|
||||
}
|
||||
|
||||
if let Some(change_to_directory) = self.maybe_change_to_directory.as_deref() {
|
||||
command = format!("cd {} && {}",
|
||||
change_to_directory,
|
||||
&command);
|
||||
}
|
||||
|
||||
if let Some(docker_options) = self.maybe_docker_options.as_ref() {
|
||||
command = docker_options.to_command_string(&command);
|
||||
}
|
||||
|
||||
info!("Running command: {}", command);
|
||||
|
||||
let result = Command::new("sh")
|
||||
.arg("-c")
|
||||
.arg(command)
|
||||
.output()?;
|
||||
|
||||
info!("Downloader Result: {:?}", result);
|
||||
|
||||
if !result.status.success() {
|
||||
let reason = String::from_utf8(result.stderr).unwrap_or("UNKNOWN".to_string());
|
||||
return Err(anyhow!("Failure to execute command: {:?}", reason))
|
||||
}
|
||||
|
||||
Ok(temp_filename)
|
||||
}
|
||||
|
||||
/// Download file from Google Drive into the `TempDir`.
|
||||
/// Return the local filesystem filename.
|
||||
pub async fn download_file(&self,
|
||||
|
||||
+55
-3
@@ -4,8 +4,8 @@ use errors::AnyhowResult;
|
||||
use crate::payloads::generic_inference_args::lipsync_payload::LipsyncArgs;
|
||||
use crate::payloads::generic_inference_args::mocap_payload::MocapArgs;
|
||||
use crate::payloads::generic_inference_args::tts_payload::TTSArgs;
|
||||
use crate::payloads::generic_inference_args::videofilter_payload::{RerenderArgs};
|
||||
|
||||
use crate::payloads::generic_inference_args::videofilter_payload::RerenderArgs;
|
||||
use crate::payloads::generic_inference_args::image_generation_payload::StableDiffusionArgs;
|
||||
|
||||
/// Used to encode extra state for the `generic_inference_jobs` table.
|
||||
/// This should act somewhat like a serialized protobuf stored inside a record.
|
||||
@@ -42,6 +42,10 @@ pub enum InferenceCategoryAbbreviated {
|
||||
#[serde(alias = "video_filter")]
|
||||
VideoFilter,
|
||||
|
||||
#[serde(rename = "ig")] // NB: DO NOT CHANGE. It could break live jobs. Renamed to be fewer bytes.
|
||||
#[serde(alias = "image_generation")]
|
||||
ImageGeneration,
|
||||
|
||||
#[serde(rename = "mc")] // NB: DO NOT CHANGE. It could break live jobs. Renamed to be fewer bytes.
|
||||
#[serde(alias = "mocap")]
|
||||
Mocap,
|
||||
@@ -98,11 +102,13 @@ pub enum PolymorphicInferenceArgs {
|
||||
/// Rerender a video. (Short name to save space when serializing.)
|
||||
Rr(RerenderArgs),
|
||||
|
||||
/// Image generation. (Short name to save space when serializing.)
|
||||
Ig(StableDiffusionArgs),
|
||||
|
||||
// Mocap (Short name to save space when serializing.)
|
||||
Mc(MocapArgs)
|
||||
}
|
||||
|
||||
|
||||
impl GenericInferenceArgs {
|
||||
|
||||
pub fn from_json(json: &str) -> AnyhowResult<Self> {
|
||||
@@ -121,6 +127,7 @@ impl InferenceCategoryAbbreviated {
|
||||
InferenceCategory::TextToSpeech => Self::TextToSpeech,
|
||||
InferenceCategory::VoiceConversion => Self::VoiceConversion,
|
||||
InferenceCategory::VideoFilter => Self::VideoFilter,
|
||||
InferenceCategory::ImageGeneration => Self::ImageGeneration,
|
||||
InferenceCategory::Mocap => Self::Mocap,
|
||||
}
|
||||
}
|
||||
@@ -131,6 +138,7 @@ impl InferenceCategoryAbbreviated {
|
||||
Self::TextToSpeech => InferenceCategory::TextToSpeech,
|
||||
Self::VoiceConversion => InferenceCategory::VoiceConversion,
|
||||
Self::VideoFilter => InferenceCategory::VideoFilter,
|
||||
Self::ImageGeneration =>InferenceCategory::ImageGeneration,
|
||||
Self::Mocap => InferenceCategory::Mocap,
|
||||
}
|
||||
}
|
||||
@@ -141,6 +149,8 @@ mod tests {
|
||||
use crate::payloads::generic_inference_args::generic_inference_args::{FundamentalFrequencyMethodForJob, GenericInferenceArgs, InferenceCategoryAbbreviated, PolymorphicInferenceArgs};
|
||||
use crate::payloads::generic_inference_args::lipsync_payload::{LipsyncAnimationAudioSource, LipsyncAnimationImageSource, LipsyncArgs};
|
||||
use crate::payloads::generic_inference_args::tts_payload::TTSArgs;
|
||||
use crate::payloads::generic_inference_args::image_generation_payload::StableDiffusionArgs;
|
||||
use tokens::tokens::{model_weights::ModelWeightToken, media_files::MediaFileToken};
|
||||
|
||||
#[test]
|
||||
fn typical_lipsync_animation_args_serialize() {
|
||||
@@ -187,6 +197,48 @@ mod tests {
|
||||
assert!(json.len() < 1000);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn typical_image_gen_args_serialize() {
|
||||
|
||||
let video_media_token = MediaFileToken("video_media_token".to_string());
|
||||
let image_media_token = MediaFileToken("image_media_token".to_string());
|
||||
let sd_model_token = ModelWeightToken("sd_model_token".to_string());
|
||||
let lora_model_token = ModelWeightToken("lora_model_token".to_string());
|
||||
|
||||
let prompt = "prompt".to_string();
|
||||
let a_prompt = "a_prompt".to_string();
|
||||
let n_prompt = "n_prompt".to_string();
|
||||
let seed = 1;
|
||||
let upload_path = "upload_path".to_string();
|
||||
let lora_upload_path = "lora_upload_path".to_string();
|
||||
let checkpoint = "checkpoint".to_string();
|
||||
let type_of_inference = "type_of_inference".to_string();
|
||||
let args = GenericInferenceArgs {
|
||||
inference_category: Some(InferenceCategoryAbbreviated::ImageGeneration),
|
||||
args: Some(PolymorphicInferenceArgs::Ig(StableDiffusionArgs {
|
||||
maybe_sd_model_token: Some(sd_model_token),
|
||||
maybe_lora_model_token: Some(lora_model_token),
|
||||
maybe_sampler: Some("sampler".as_ref()),
|
||||
maybe_height: Some(512),
|
||||
maybe_width: Some(512),
|
||||
maybe_cfg_scale: Some(7),
|
||||
maybe_prompt: Some(prompt),
|
||||
maybe_n_prompt: Some(n_prompt),
|
||||
maybe_batch_count: Some(1),
|
||||
maybe_number_of_samples: Some(25),
|
||||
maybe_seed: Some(seed),
|
||||
maybe_upload_path: Some(upload_path),
|
||||
maybe_lora_upload_path: Some(lora_upload_path),
|
||||
type_of_inference: type_of_inference,
|
||||
description: Some("Option".as_ref()),
|
||||
title: Some("Model Name".as_ref())
|
||||
})),
|
||||
};
|
||||
|
||||
let json = serde_json::ser::to_string(&args).unwrap();
|
||||
assert_eq!(json, r#"{"cat":"ig","args":{"Ig":{"vs":"video_media_token","is":"image_media_token","sd":"sd_model_token","lm":"lora_model_token","p":"prompt","ap":"a_prompt","np":"n_prompt","se":1,"mu":"upload_path","lu":"lora_upload_path"}}}"#.to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn typical_voice_conversion_args_serialize() {
|
||||
let args = GenericInferenceArgs {
|
||||
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
use tokens::tokens::{model_weights::ModelWeightToken, media_files::MediaFileToken};
|
||||
|
||||
/// Video sources can be one of several:
|
||||
/// - F: media_files (todo)
|
||||
/// - U: media_uploads (legacy)
|
||||
|
||||
/// For image to image we probably want images
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub enum StableDiffusionSource {
|
||||
// NB: DO NOT CHANGE. It could break live jobs. Renamed to be fewer bytes.
|
||||
/// Media File Token (media_files table)
|
||||
/// Serde cannot yet rename enum variants.
|
||||
F(String),
|
||||
|
||||
// NB: DO NOT CHANGE. It could break live jobs. Renamed to be fewer bytes.
|
||||
/// Media Upload Token (media_uploads table)
|
||||
/// Serde cannot yet rename enum variants.
|
||||
U(String),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct StableDiffusionArgs {
|
||||
|
||||
#[serde(rename = "sd")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub maybe_sd_model_token: Option<ModelWeightToken>,
|
||||
|
||||
#[serde(rename = "lm")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub maybe_lora_model_token: Option<ModelWeightToken>,
|
||||
|
||||
#[serde(rename = "w")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub maybe_width: Option<i32>,
|
||||
|
||||
#[serde(rename = "h")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub maybe_height: Option<i32>,
|
||||
|
||||
#[serde(rename = "s")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub maybe_sampler: Option<String>,
|
||||
|
||||
#[serde(rename = "p")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub maybe_prompt: Option<String>,
|
||||
|
||||
#[serde(rename = "np")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub maybe_n_prompt: Option<String>,
|
||||
|
||||
#[serde(rename = "se")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub maybe_seed: Option<i64>,
|
||||
|
||||
#[serde(rename = "mu")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub maybe_upload_path: Option<String>,
|
||||
|
||||
#[serde(rename = "cf")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub maybe_cfg_scale: Option<i32>,
|
||||
|
||||
#[serde(rename = "lu")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub maybe_lora_upload_path: Option<String>,
|
||||
|
||||
#[serde(rename = "sa")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub maybe_number_of_samples: Option<i32>,
|
||||
|
||||
#[serde(rename = "bc")]
|
||||
pub maybe_batch_count: Option<i32>,
|
||||
|
||||
#[serde(rename = "t")]
|
||||
pub type_of_inference: String,
|
||||
|
||||
// loRA / checkpoint description
|
||||
#[serde(rename = "de")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub description: Option<String>,
|
||||
// loRA / checkpoint name and description
|
||||
#[serde(rename = "na")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub name: Option<String>
|
||||
}
|
||||
|
||||
|
||||
@@ -2,4 +2,5 @@ pub mod generic_inference_args;
|
||||
pub mod lipsync_payload;
|
||||
pub mod tts_payload;
|
||||
pub mod videofilter_payload;
|
||||
pub mod mocap_payload;
|
||||
pub mod image_generation_payload;
|
||||
pub mod mocap_payload;
|
||||
|
||||
+52
-8
@@ -11,22 +11,27 @@ pub struct BatchEntry {
|
||||
pub entity: BatchGenerationEntity,
|
||||
}
|
||||
|
||||
pub struct InsertBatchArgs<'a> {
|
||||
pub entries: Vec<BatchEntry>,
|
||||
pub transaction: &'a mut Transaction<'a, MySql>,
|
||||
pub struct InsertBatchArgs<'a, 'b> {
|
||||
pub entries: Vec<BatchGenerationEntity>,
|
||||
pub transaction: &'a mut Transaction<'b, MySql>,
|
||||
}
|
||||
|
||||
/// NB: Caller is responsible for rolling back the transaction if this fails.
|
||||
pub async fn insert_batch_generation_records(args: InsertBatchArgs<'_>) -> AnyhowResult<()> {
|
||||
/// Insert a list of entities into a "batch" together for grouping; returns the new batch token identifier to return
|
||||
/// to the HTTP caller.
|
||||
///
|
||||
/// NB: Calling code is responsible for rolling back the transaction if this fails.
|
||||
pub async fn insert_batch_generation_records<'a, 'b>(args: InsertBatchArgs<'a, 'b>) -> AnyhowResult<BatchGenerationToken> {
|
||||
let batch_token = BatchGenerationToken::generate();
|
||||
|
||||
let mut query_builder = QueryBuilder::new(r#"
|
||||
INSERT INTO batch_generations (token, entity_type, entity_token) VALUES
|
||||
"#);
|
||||
|
||||
for (i, entry) in args.entries.iter().enumerate() {
|
||||
let (entity_type, entity_token) = entry.entity.get_composite_keys();
|
||||
let (entity_type, entity_token) = entry.get_composite_keys();
|
||||
|
||||
query_builder.push("(");
|
||||
query_builder.push_bind(&entry.batch_token);
|
||||
query_builder.push_bind(&batch_token);
|
||||
query_builder.push(",");
|
||||
|
||||
query_builder.push_bind(entity_type);
|
||||
@@ -45,10 +50,49 @@ pub async fn insert_batch_generation_records(args: InsertBatchArgs<'_>) -> Anyho
|
||||
let query_result = query.execute(&mut **args.transaction).await;
|
||||
|
||||
match query_result {
|
||||
Ok(_) => Ok(()),
|
||||
Ok(_) => Ok(batch_token),
|
||||
Err(err) => {
|
||||
error!("Error with batch generation query: {:?}", &err);
|
||||
Err(anyhow!("model category creation error: {:?}", &err))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[ignore]
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use sqlx::mysql::MySqlPoolOptions;
|
||||
use composite_identifiers::by_table::batch_generations::batch_generation_entity::BatchGenerationEntity;
|
||||
use config::shared_constants::DEFAULT_MYSQL_CONNECTION_STRING;
|
||||
use tokens::tokens::media_files::MediaFileToken;
|
||||
use crate::queries::batch_generations::insert_batch_generation_records::{insert_batch_generation_records, InsertBatchArgs};
|
||||
|
||||
async fn setup() -> sqlx::Pool<sqlx::MySql> {
|
||||
MySqlPoolOptions::new()
|
||||
.max_connections(3)
|
||||
.connect(&DEFAULT_MYSQL_CONNECTION_STRING).await
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[ignore]
|
||||
#[tokio::test]
|
||||
async fn test() {
|
||||
let pool = setup().await;
|
||||
|
||||
let mut transaction = pool.begin().await.unwrap();
|
||||
|
||||
let entries = vec![
|
||||
BatchGenerationEntity::MediaFile(MediaFileToken::new_from_str("media_foo")),
|
||||
BatchGenerationEntity::MediaFile(MediaFileToken::new_from_str("media_bar")),
|
||||
BatchGenerationEntity::MediaFile(MediaFileToken::new_from_str("media_baz")),
|
||||
];
|
||||
|
||||
let r = insert_batch_generation_records(InsertBatchArgs {
|
||||
entries,
|
||||
transaction: &mut transaction,
|
||||
}).await;
|
||||
|
||||
transaction.commit().await.unwrap();
|
||||
}
|
||||
}
|
||||
@@ -179,6 +179,7 @@ fn raw_record_to_public_result(record: RawGenericInferenceJobStatus) -> GenericI
|
||||
InferenceCategory::TextToSpeech => record.maybe_tts_model_title.as_deref(),
|
||||
InferenceCategory::VoiceConversion => record.maybe_voice_conversion_model_title.as_deref(),
|
||||
InferenceCategory::VideoFilter => Some("Video Filter"),
|
||||
InferenceCategory::ImageGeneration => Some("Image Generation"),
|
||||
InferenceCategory::Mocap => Some("Mocap"),
|
||||
};
|
||||
|
||||
@@ -189,6 +190,7 @@ fn raw_record_to_public_result(record: RawGenericInferenceJobStatus) -> GenericI
|
||||
InferenceCategory::TextToSpeech => (false, record.maybe_tts_public_bucket_path.as_deref()),
|
||||
InferenceCategory::VoiceConversion => (true, record.maybe_voice_conversion_public_bucket_hash.as_deref()),
|
||||
InferenceCategory::VideoFilter => (true, record.maybe_media_file_public_bucket_directory_hash.as_deref()),
|
||||
InferenceCategory::ImageGeneration => (true, record.maybe_media_file_public_bucket_directory_hash.as_deref()),
|
||||
InferenceCategory::Mocap => (true, record.maybe_media_file_public_bucket_directory_hash.as_deref()),
|
||||
};
|
||||
|
||||
|
||||
+1
-1
@@ -66,7 +66,7 @@ pub async fn insert_media_file_from_zero_shot(
|
||||
maybe_creator_category_synthetic_id = Some(next_lipsync_id);
|
||||
}
|
||||
|
||||
// TODO: Ask if it make sense to use ONE function to do the insert
|
||||
// TODO: Ask if it make sense to use ONE function to do the insert * I agree it does .... use insert media file generic and eventually remove all this.
|
||||
// Since fill this out apart of the funtion this seems like the only thing to change.
|
||||
const ORIGIN_CATEGORY : MediaFileOriginCategory = MediaFileOriginCategory::Inference;
|
||||
const ORIGIN_PRODUCT_CATEGORY : MediaFileOriginProductCategory = MediaFileOriginProductCategory::ZeroShotVoice;
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
use anyhow::anyhow;
|
||||
use sqlx;
|
||||
use sqlx::MySqlPool;
|
||||
|
||||
use enums::by_table::generic_synthetic_ids::id_category::IdCategory;
|
||||
use enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory;
|
||||
use enums::by_table::media_files::media_file_origin_model_type::MediaFileOriginModelType;
|
||||
use enums::by_table::media_files::media_file_origin_product_category::MediaFileOriginProductCategory;
|
||||
use enums::by_table::media_files::media_file_type::MediaFileType;
|
||||
use errors::AnyhowResult;
|
||||
use tokens::tokens::media_files::MediaFileToken;
|
||||
use tokens::tokens::weight_model_weight;
|
||||
use tokens::tokens::users::UserToken;
|
||||
|
||||
use crate::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob;
|
||||
use crate::queries::generic_synthetic_ids::transactional_increment_generic_synthetic_id::transactional_increment_generic_synthetic_id;
|
||||
// thought about this it seems like this can be a bit more geneneric instead of having this we can ...
|
||||
pub struct InsertArgs<'a> {
|
||||
pub pool: &'a MySqlPool,
|
||||
pub job: &'a AvailableInferenceJob,
|
||||
|
||||
pub maybe_mime_type: Option<&'a str>,
|
||||
pub file_size_bytes: u64,
|
||||
pub sha256_checksum: &'a str,
|
||||
|
||||
pub public_bucket_directory_hash: &'a str,
|
||||
pub maybe_public_bucket_prefix: Option<&'a str>,
|
||||
pub maybe_public_bucket_extension: Option<&'a str>,
|
||||
|
||||
pub is_on_prem: bool,
|
||||
|
||||
pub worker_hostname: &'a str,
|
||||
pub worker_cluster: &'a str,
|
||||
|
||||
pub maybe_creator_user_token: Option<&'a UserToken>,
|
||||
pub maybe_creator_anonymous_visitor_token: Option<&'a AnonymousVisitorTrackingToken>,
|
||||
pub creator_ip_address: &'a str,
|
||||
pub creator_set_visibility: Visibility,
|
||||
pub upload_type: UploadType,
|
||||
pub media_file_type: MediaFileType,
|
||||
pub duration_millis: u64,
|
||||
|
||||
pub media_file_origin: MediaFileOriginProductCategory,
|
||||
pub media_file_origin_product_category: MediaFileOriginProductCategory,
|
||||
pub media_file_origin_model_type: Mediafile,
|
||||
pub maybe_origin_filename: String,
|
||||
pub maybe_origin_model_token:WeightsModelToken
|
||||
}
|
||||
pub async fn insert_media_file_generic(
|
||||
args: InsertArgs<'_>
|
||||
) -> AnyhowResult<(MediaFileToken, u64)>
|
||||
{
|
||||
|
||||
let result_token = MediaFileToken::generate();
|
||||
|
||||
let mut maybe_creator_file_synthetic_id : Option<u64> = None;
|
||||
let mut maybe_creator_category_synthetic_id : Option<u64> = None;
|
||||
|
||||
let mut transaction = args.pool.begin().await?;
|
||||
|
||||
// create a user token
|
||||
if let Some(creator_user_token) = args.job.maybe_creator_user_token.as_deref() {
|
||||
let user_token = UserToken::new_from_str(creator_user_token);
|
||||
|
||||
let next_media_file_id = transactional_increment_generic_synthetic_id(
|
||||
&user_token,
|
||||
IdCategory::MediaFile,
|
||||
&mut transaction
|
||||
).await?;
|
||||
|
||||
let next_lipsync_id = transactional_increment_generic_synthetic_id(
|
||||
&user_token,
|
||||
IdCategory::ZeroShotTtsResult,
|
||||
&mut transaction
|
||||
).await?;
|
||||
|
||||
maybe_creator_file_synthetic_id = Some(next_media_file_id);
|
||||
maybe_creator_category_synthetic_id = Some(next_lipsync_id);
|
||||
}
|
||||
|
||||
// TODO: Ask if it make sense to use ONE function to do the insert * I agree it does .... use insert media file generic and eventually remove all this.
|
||||
// Since fill this out apart of the funtion this seems like the only thing to change.
|
||||
const ORIGIN_CATEGORY : MediaFileOriginCategory = MediaFileOriginCategory::Inference;
|
||||
const ORIGIN_PRODUCT_CATEGORY : MediaFileOriginProductCategory = MediaFileOriginProductCategory::ZeroShotVoice;
|
||||
const ORIGIN_MODEL_TYPE : MediaFileOriginModelType = MediaFileOriginModelType::VallEX;
|
||||
const MEDIA_TYPE : MediaFileType = MediaFileType::Audio;
|
||||
|
||||
let record_id = {
|
||||
let query_result = sqlx::query!(
|
||||
r#"
|
||||
INSERT INTO media_files
|
||||
SET
|
||||
token = ?,
|
||||
|
||||
origin_category = ?,
|
||||
origin_product_category = ?,
|
||||
maybe_origin_model_type = ?,
|
||||
|
||||
media_type = ?,
|
||||
maybe_mime_type = ?,
|
||||
file_size_bytes = ?,
|
||||
|
||||
checksum_sha2 = ?,
|
||||
|
||||
public_bucket_directory_hash = ?,
|
||||
maybe_public_bucket_prefix = ?,
|
||||
maybe_public_bucket_extension = ?,
|
||||
|
||||
maybe_creator_user_token = ?,
|
||||
maybe_creator_anonymous_visitor_token = ?,
|
||||
creator_ip_address = ?,
|
||||
|
||||
creator_set_visibility = ?,
|
||||
|
||||
maybe_creator_file_synthetic_id = ?,
|
||||
maybe_creator_category_synthetic_id = ?,
|
||||
|
||||
is_generated_on_prem = ?,
|
||||
generated_by_worker = ?,
|
||||
generated_by_cluster = ?
|
||||
|
||||
"#,
|
||||
result_token.as_str(),
|
||||
|
||||
ORIGIN_CATEGORY.to_str(),
|
||||
ORIGIN_PRODUCT_CATEGORY.to_str(),
|
||||
ORIGIN_MODEL_TYPE.to_str(),
|
||||
|
||||
MEDIA_TYPE.to_str(),
|
||||
args.maybe_mime_type,
|
||||
args.file_size_bytes,
|
||||
|
||||
args.sha256_checksum,
|
||||
|
||||
args.public_bucket_directory_hash,
|
||||
args.maybe_public_bucket_prefix,
|
||||
args.maybe_public_bucket_extension,
|
||||
|
||||
args.job.maybe_creator_user_token,
|
||||
args.job.maybe_creator_anonymous_visitor_token,
|
||||
args.job.creator_ip_address,
|
||||
|
||||
args.job.creator_set_visibility.to_str(),
|
||||
|
||||
maybe_creator_file_synthetic_id,
|
||||
maybe_creator_category_synthetic_id,
|
||||
|
||||
args.is_on_prem,
|
||||
args.worker_hostname,
|
||||
args.worker_cluster
|
||||
)
|
||||
.execute(&mut *transaction)
|
||||
.await;
|
||||
|
||||
let record_id = match query_result {
|
||||
Ok(res) => {
|
||||
res.last_insert_id()
|
||||
},
|
||||
Err(err) => {
|
||||
// TODO: handle better
|
||||
//transaction.rollback().await?;
|
||||
return Err(anyhow!("Mysql error: {:?}", err));
|
||||
}
|
||||
};
|
||||
|
||||
record_id
|
||||
};
|
||||
|
||||
transaction.commit().await?;
|
||||
|
||||
Ok((result_token, record_id))
|
||||
}
|
||||
@@ -293,6 +293,8 @@ mod tests {
|
||||
maybe_scoped_weight_type: None,
|
||||
maybe_scoped_weight_category: None,
|
||||
mysql_pool: &pool,
|
||||
maybe_scoped_weight_type: None,
|
||||
maybe_scoped_weight_category: None,
|
||||
}).await?;
|
||||
for weight in weights_by_username.records.iter() {
|
||||
// print weight
|
||||
|
||||
@@ -76,6 +76,8 @@ pub async fn do_process_single_job(job_state: &JobState, job: &AvailableDownload
|
||||
return Err(anyhow!("Bad download URL: `{}`", &job.download_url));
|
||||
}
|
||||
|
||||
// TODO USE THIS DOWNLOADER
|
||||
|
||||
let download_filename = match job_state.sidecar_configs.google_drive_downloader.download_file(&job.download_url, &temp_dir).await {
|
||||
Ok(filename) => filename,
|
||||
Err(e) => {
|
||||
|
||||
@@ -70,7 +70,7 @@ pub struct PretrainedModels {
|
||||
|
||||
/// Configurations and interfaces to code deployed as sidecars or container mounts.
|
||||
pub struct SidecarConfigs {
|
||||
pub google_drive_downloader: GoogleDriveDownloadCommand,
|
||||
pub(crate) google_drive_downloader: GoogleDriveDownloadCommand,
|
||||
pub rvc_v2_model_check_command: RvcV2ModelCheckCommand,
|
||||
pub softvc_model_check_command: SoftVcModelCheckCommand,
|
||||
pub so_vits_svc_model_check_command: SoVitsSvcModelCheckCommand,
|
||||
|
||||
@@ -19,6 +19,7 @@ actix_helpers = { path = "../../../lib/actix_helpers" }
|
||||
bootstrap = { path = "../../../lib/bootstrap" }
|
||||
buckets = { path = "../../../_types/buckets" }
|
||||
cloud_storage = { path = "../../../lib/api_clients/cloud_storage" }
|
||||
google_drive_common = { path = "../../../lib/api_clients/google_drive_common" }
|
||||
collections = { path = "../../../lib/collections" }
|
||||
composite_identifiers = { path = "../../../_types/composite_identifiers" }
|
||||
concurrency = { path = "../../../lib/concurrency" }
|
||||
|
||||
@@ -104,6 +104,14 @@ VITS_INFERENCE_MAYBE_DOCKER_IMAGE_SHA="03017896367b"
|
||||
RERENDER_INFERENCE_ROOT_DIRECTORY="/home/salt/clone/storyteller-ml/animation/rerender-lora/"
|
||||
RERENDER_INFERENCE_EXECUTABLE_OR_COMMAND="venv/bin/python rerender.py"
|
||||
|
||||
# ================================= #
|
||||
# #
|
||||
# STABLE DIFFUSION #
|
||||
# #
|
||||
# ================================= #
|
||||
STABLE_DIFFUSION_INFERENCE_ROOT_DIRECTORY="/home/tensor/code/storyteller/storyteller-ml/image_generation/Storyteller-Studio-Filter/"
|
||||
STABLE_DIFFUSION_INFERENCE_COMMAND=".venv/bin/python main.py"
|
||||
|
||||
# ================================= #
|
||||
# #
|
||||
# MocapNET #
|
||||
|
||||
@@ -188,7 +188,7 @@ async fn get_model_record_from_cacheable_query(job_dependencies: &JobDependencie
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
warn!("Job does not have a category or a model token: {:?} - category: {:?}, token: {:?}",
|
||||
warn!("Only applies to older job workflows. Job does not have a category or a model token: {:?} - category: {:?}, token: {:?}",
|
||||
job.id, job.inference_category, job.maybe_model_token);
|
||||
|
||||
MaybeInferenceModel::None
|
||||
|
||||
@@ -17,6 +17,7 @@ use crate::job::job_types::lipsync::process_single_lipsync_job::process_single_l
|
||||
use crate::job::job_types::tts::process_single_tts_job::process_single_tts_job;
|
||||
use crate::job::job_types::vc::process_single_vc_job::process_single_vc_job;
|
||||
use crate::job::job_types::videofilter::process_single_vf_job::process_single_vf_job;
|
||||
use crate::job::job_types::image_generation::process_single_ig_job::process_single_ig_job;
|
||||
use crate::job::job_types::mocap::process_single_mc_job::process_single_mc_job;
|
||||
use crate::job_dependencies::JobDependencies;
|
||||
|
||||
@@ -187,6 +188,9 @@ async fn do_process_single_job(
|
||||
InferenceCategory::VideoFilter => {
|
||||
process_single_vf_job(job_dependencies, job).await?
|
||||
}
|
||||
InferenceCategory::ImageGeneration => {
|
||||
process_single_ig_job(job_dependencies, job).await?
|
||||
}
|
||||
InferenceCategory::Mocap => {
|
||||
process_single_mc_job(job_dependencies, job).await?
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
pub mod process_single_ig_job;
|
||||
pub mod sd;
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
use enums::by_table::generic_inference_jobs::inference_model_type::InferenceModelType;
|
||||
use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob;
|
||||
use crate::job::job_loop::job_success_result::JobSuccessResult;
|
||||
use crate::job::job_loop::process_single_job_error::ProcessSingleJobError;
|
||||
use crate::job::job_types::image_generation::sd::process_job::process_job_selection;
|
||||
use crate::job_dependencies::JobDependencies;
|
||||
use crate::job::job_types::image_generation::sd::process_job::StableDiffusionProcessArgs;
|
||||
use errors::anyhow;
|
||||
|
||||
pub async fn process_single_ig_job(job_dependencies: &JobDependencies, job: &AvailableInferenceJob) -> Result<JobSuccessResult, ProcessSingleJobError> {
|
||||
let job = job;
|
||||
match job.maybe_model_type {
|
||||
Some(InferenceModelType::StableDiffusion) => {
|
||||
dispatch_sd_job(
|
||||
job_dependencies,
|
||||
job
|
||||
).await
|
||||
},
|
||||
Some(other_model_type) => {
|
||||
Err(ProcessSingleJobError::Other(anyhow!("Wrong model type for SD: {:?}", other_model_type)))
|
||||
}
|
||||
None => {
|
||||
Err(ProcessSingleJobError::Other(anyhow!("SD model type not set")))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn dispatch_sd_job(job_dependencies: &JobDependencies, job: &AvailableInferenceJob) -> Result<JobSuccessResult, ProcessSingleJobError> {
|
||||
let args = StableDiffusionProcessArgs {
|
||||
job_dependencies,
|
||||
job,
|
||||
};
|
||||
process_job_selection(args).await
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
pub mod process_job;
|
||||
|
||||
pub mod model_downloaders;
|
||||
pub mod sd_inference_command;
|
||||
pub mod stable_diffusion_dependencies;
|
||||
pub mod validate_inputs;
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
|
||||
crate::impl_model_downloader!(
|
||||
SDVAEEncoder,
|
||||
"SD Variation Auto Encoder",
|
||||
"SD_VARIATIONAL_AUTO_ENCODER_BUCKET_PATH",
|
||||
"/animation_sadtalker/enhancer/parsing_parsenet.pth",
|
||||
"SD_VARIATIONAL_AUTO_ENCODER_FILESYSTEM_PATH",
|
||||
"/tmp/downloads/sadtalker/parsing_parsenet.pth"
|
||||
);
|
||||
|
||||
pub struct StableDiffusionDownloaders {
|
||||
sd_vae_encoder: SDVAEEncoder
|
||||
}
|
||||
impl StableDiffusionDownloaders {
|
||||
pub fn build_all_from_env() -> Self {
|
||||
Self {
|
||||
sd_vae_encoder: SDVAEEncoder::from_env(),
|
||||
}
|
||||
}
|
||||
}
|
||||
+495
@@ -0,0 +1,495 @@
|
||||
use std::env::temp_dir;
|
||||
use std::ops::Deref;
|
||||
use std::path::PathBuf;
|
||||
use std::thread;
|
||||
use std::thread::Thread;
|
||||
use std::time::{Duration, Instant};
|
||||
use cloud_storage::remote_file_manager::remote_cloud_bucket_details::RemoteCloudBucketDetails;
|
||||
use mysql_queries::payloads::generic_inference_args::image_generation_payload::StableDiffusionArgs;
|
||||
use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob;
|
||||
use mysql_queries::queries::model_weights::get_weight::get_weight_by_token;
|
||||
use crate::job::job_loop::job_success_result::{ JobSuccessResult, ResultEntity };
|
||||
use crate::job::job_loop::process_single_job_error::ProcessSingleJobError;
|
||||
use crate::job_dependencies::JobDependencies;
|
||||
use anyhow::anyhow;
|
||||
use log::info;
|
||||
use sqlx::MySqlPool;
|
||||
use cloud_storage::remote_file_manager::media_descriptor::MediaImagePngDescriptor;
|
||||
use mysql_queries::payloads::generic_inference_args::generic_inference_args::PolymorphicInferenceArgs;
|
||||
|
||||
use cloud_storage::remote_file_manager::remote_cloud_file_manager::RemoteCloudFileClient;
|
||||
use cloud_storage::remote_file_manager::weights_descriptor::WeightsLoRADescriptor;
|
||||
use enums::by_table::generic_inference_jobs::inference_result_type::InferenceResultType::UploadModel;
|
||||
use enums::by_table::generic_synthetic_ids::id_category::IdCategory::MediaFile;
|
||||
use enums::by_table::media_files::media_file_type::MediaFileType;
|
||||
use enums::by_table::media_uploads::media_upload_source::MediaUploadSource;
|
||||
use enums::by_table::media_uploads::media_upload_type::MediaUploadType;
|
||||
use enums::by_table::model_weights::weights_category::WeightsCategory;
|
||||
use enums::by_table::model_weights::weights_types::WeightsType;
|
||||
use enums::common::visibility::Visibility;
|
||||
use filesys::path_to_string::path_to_string;
|
||||
use filesys::safe_delete_temp_directory::safe_delete_temp_directory;
|
||||
use mysql_queries::payloads::media_upload_modification_details::MediaUploadModificationDetails;
|
||||
use mysql_queries::queries::media_files::create::insert_media_file_from_file_upload::{insert_media_file_from_file_upload, InsertMediaFileFromUploadArgs, UploadType};
|
||||
use mysql_queries::queries::media_uploads::insert_media_upload::{Args, insert_media_upload};
|
||||
use tokens::tokens::anonymous_visitor_tracking::AnonymousVisitorTrackingToken;
|
||||
use tokens::tokens::model_weights::ModelWeightToken;
|
||||
use tokens::tokens::users::UserToken;
|
||||
use crate::job::job_types::image_generation::sd::sd_inference_command::InferenceArgs;
|
||||
use crate::job::job_types::image_generation::sd::stable_diffusion_dependencies::StableDiffusionDependencies;
|
||||
use crate::job::job_types::image_generation::sd::validate_inputs::validate_inputs;
|
||||
|
||||
use google_drive_common::google_drive_download_command::GoogleDriveDownloadCommand;
|
||||
use mysql_queries::queries::model_weights::create::create_weight::{create_weight, CreateModelWeightsArgs};
|
||||
|
||||
pub struct StableDiffusionProcessArgs<'a> {
|
||||
pub job_dependencies: &'a JobDependencies,
|
||||
pub job: &'a AvailableInferenceJob,
|
||||
}
|
||||
|
||||
|
||||
// run inference
|
||||
// insert record into the db with the inference job token complete.
|
||||
|
||||
pub async fn sd_args_from_job(
|
||||
args: &StableDiffusionProcessArgs<'_>
|
||||
) -> Result<StableDiffusionArgs, ProcessSingleJobError> {
|
||||
let inference_args = args.job.maybe_inference_args
|
||||
.as_ref()
|
||||
.map(|args| args.args.as_ref())
|
||||
.flatten();
|
||||
let polymorphic_args = match inference_args {
|
||||
Some(args) => args,
|
||||
None => {
|
||||
return Err(
|
||||
ProcessSingleJobError::from_anyhow_error(anyhow!("no inference args for job!"))
|
||||
);
|
||||
}
|
||||
};
|
||||
let sd_args = match polymorphic_args {
|
||||
PolymorphicInferenceArgs::Ig(args) => args,
|
||||
_ => {
|
||||
return Err(
|
||||
ProcessSingleJobError::from_anyhow_error(anyhow!("wrong inner args for job!"))
|
||||
);
|
||||
}
|
||||
};
|
||||
let stable_diffusion_args: StableDiffusionArgs = StableDiffusionArgs::from(sd_args.clone());
|
||||
Ok(stable_diffusion_args)
|
||||
}
|
||||
|
||||
// store the prompt and cluster them today.
|
||||
|
||||
pub async fn process_job_selection (args: StableDiffusionProcessArgs<'_>
|
||||
) -> Result<JobSuccessResult, ProcessSingleJobError> {
|
||||
let job = args.job;
|
||||
let sd_args = sd_args_from_job(&args).await?;
|
||||
if sd_args.type_of_inference == "inference" {
|
||||
process_job_inference(&args).await
|
||||
}
|
||||
else if sd_args.type_of_inference == "lora" {
|
||||
process_job_lora(&args).await
|
||||
}
|
||||
else if sd_args.type_of_inference == "checkpoint"{
|
||||
process_job_inference(&args).await
|
||||
}
|
||||
else {
|
||||
Err(ProcessSingleJobError::Other(anyhow!("inference type doesn't exist!")))
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn process_job_checkpoint(args: &StableDiffusionProcessArgs<'_>) -> Result<JobSuccessResult, ProcessSingleJobError> {
|
||||
|
||||
// insert model record in create model record
|
||||
|
||||
// let maybe_result_entity = ResultEntity {
|
||||
// entity_type: InferenceResultType::UploadModel,
|
||||
// entity_token:
|
||||
// };
|
||||
Ok(JobSuccessResult {
|
||||
maybe_result_entity: None,
|
||||
inference_duration: Duration::from_secs(0),
|
||||
})
|
||||
}
|
||||
pub async fn process_job_lora(args: &StableDiffusionProcessArgs<'_>) -> Result<JobSuccessResult, ProcessSingleJobError> {
|
||||
Ok(JobSuccessResult {
|
||||
maybe_result_entity: None,
|
||||
inference_duration: Duration::from_secs(0),
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn process_job_inference(
|
||||
args: &StableDiffusionProcessArgs<'_>
|
||||
) -> Result<JobSuccessResult, ProcessSingleJobError> {
|
||||
let job = args.job;
|
||||
let deps = args.job_dependencies;
|
||||
let mysql_pool = &deps.db.mysql_pool;
|
||||
|
||||
|
||||
let sd_args = sd_args_from_job(&args).await?;
|
||||
let sd_deps = match &args.job_dependencies.job.job_specific_dependencies.maybe_stable_diffusion_dependencies {
|
||||
None => {
|
||||
return Err(ProcessSingleJobError::Other(anyhow!("Missing Job Specific Dependencies")));
|
||||
}
|
||||
Some(val) => {
|
||||
val
|
||||
}
|
||||
};
|
||||
|
||||
let creator_user_token:UserToken;
|
||||
match &job.maybe_creator_user_token {
|
||||
Some(token) => {
|
||||
creator_user_token = UserToken::new_from_str(token);
|
||||
},
|
||||
None => {
|
||||
return Err(ProcessSingleJobError::InvalidJob(anyhow!("Missing Creator User Token")));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let mut job_progress_reporter = args.job_dependencies.clients.job_progress_reporter
|
||||
.new_generic_inference(job.inference_job_token.as_str())
|
||||
.map_err(|e| ProcessSingleJobError::Other(anyhow!(e)))?;
|
||||
//==================== TEMP DIR ==================== //
|
||||
|
||||
let work_temp_dir = format!("temp_stable_diffusion_inference_{}", job.id.0);
|
||||
|
||||
// thread::sleep(seconds) to check the directory
|
||||
|
||||
//NB: TempDir exists until it goes out of scope, at which point it should delete from filesystem.
|
||||
let mut work_temp_dir = args.job_dependencies.fs.scoped_temp_dir_creator_for_work
|
||||
.new_tempdir(&work_temp_dir)
|
||||
.map_err(|e| ProcessSingleJobError::from_io_error(e))?;
|
||||
|
||||
|
||||
let sd_checkpoint_path = work_temp_dir.path().join("sd_checkpoint.safetensors");
|
||||
let lora_path = work_temp_dir.path().join("lora.safetensors");
|
||||
let vae_path = work_temp_dir.path().join("vae.safetensors");
|
||||
let output_path = work_temp_dir.path().join("output");
|
||||
let g_drive_path = work_temp_dir.path().join("gdrive");
|
||||
|
||||
info!("Paths to download to:");
|
||||
info!("sd_checkpoint_path:{}",sd_checkpoint_path.display());
|
||||
info!("lora_path:{}",lora_path.display());
|
||||
info!("vae_path:{}",vae_path.display());
|
||||
info!("output_path:{}",output_path.display());
|
||||
info!("tmp_google_drive_path:{}",g_drive_path.display());
|
||||
|
||||
// If it is not inference then it must be loRA or checkpoint downloading
|
||||
if sd_args.type_of_inference != "inference" {
|
||||
let mut download_url= String::from("");
|
||||
|
||||
if sd_args.type_of_inference == "lora" {
|
||||
download_url = match sd_args.maybe_lora_upload_path {
|
||||
Some(val) => { val },
|
||||
None => { "".to_string() }
|
||||
};
|
||||
}
|
||||
else if sd_args.type_of_inference == "checkpoint" {
|
||||
download_url = match sd_args.maybe_upload_path {
|
||||
Some(val) => { val },
|
||||
None => { "".to_string() }
|
||||
}
|
||||
}
|
||||
|
||||
if download_url.len() <= 0 {
|
||||
return Err(ProcessSingleJobError::from_anyhow_error(anyhow!("Failed to Download URL Missing")));
|
||||
}
|
||||
let file_name = "download.safetensors";
|
||||
let download_script = easyenv::get_env_string_or_default(
|
||||
"DOWNLOAD_SCRIPT",
|
||||
"./scripts/download_internet_file.py");
|
||||
let google_drive_downloader =
|
||||
GoogleDriveDownloadCommand::new_production(&download_script);
|
||||
info!("Downloading {}",download_url);
|
||||
let download_filename = match google_drive_downloader.download_file_with_file_name(&download_url, &work_temp_dir,file_name).await {
|
||||
Ok(filename) => filename,
|
||||
Err(e) => {
|
||||
return Err(ProcessSingleJobError::from_anyhow_error(anyhow!("Failed to Download")));
|
||||
}
|
||||
};
|
||||
let download_file_path = work_temp_dir.path().join(file_name);
|
||||
info!("File Retrieved at {}",download_file_path.display());
|
||||
}
|
||||
|
||||
// // Unpack loRA and Checkpoint
|
||||
// // run inference by downloading from google drive.
|
||||
let lora_token = sd_args.maybe_lora_model_token;
|
||||
let weight_token = sd_args.maybe_sd_model_token;
|
||||
|
||||
let retrieved_sd_record = match weight_token {
|
||||
Some(token) => {
|
||||
let retrieved_sd_record = get_weight_by_token(
|
||||
&token,
|
||||
false,
|
||||
&deps.db.mysql_pool
|
||||
).await?;
|
||||
match retrieved_sd_record {
|
||||
Some(record) => record,
|
||||
None => {
|
||||
return Err(
|
||||
ProcessSingleJobError::from_anyhow_error(anyhow!("no record of model!"))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
return Err(
|
||||
ProcessSingleJobError::from_anyhow_error(anyhow!("no sd model token for job!"))
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// ignore if no lora token
|
||||
let retrieved_loRA_record = match lora_token {
|
||||
Some(token) => {
|
||||
let retrieved_loRA_record = get_weight_by_token(
|
||||
&token,
|
||||
false,
|
||||
&deps.db.mysql_pool
|
||||
).await?;
|
||||
Some(retrieved_loRA_record)
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
|
||||
let remote_cloud_file_client = RemoteCloudFileClient::get_remote_cloud_file_client().await?;
|
||||
|
||||
// Details for SD checkpoint
|
||||
let details = RemoteCloudBucketDetails::new(
|
||||
retrieved_sd_record.public_bucket_hash.clone(),
|
||||
retrieved_sd_record.maybe_public_bucket_prefix.clone().unwrap_or_else(|| "".to_string()),
|
||||
retrieved_sd_record.maybe_public_bucket_extension.clone().unwrap_or_else(|| "".to_string())
|
||||
);
|
||||
remote_cloud_file_client.download_file(details, path_to_string(sd_checkpoint_path.clone())).await?;
|
||||
|
||||
match retrieved_loRA_record {
|
||||
Some(record) => {
|
||||
match record {
|
||||
Some(model_weight_record) => {
|
||||
|
||||
let lora_details = RemoteCloudBucketDetails::new(
|
||||
model_weight_record.public_bucket_hash.clone(),
|
||||
model_weight_record.maybe_public_bucket_prefix
|
||||
.clone()
|
||||
.unwrap_or_else(|| "".to_string()),
|
||||
model_weight_record.maybe_public_bucket_extension
|
||||
.clone()
|
||||
.unwrap_or_else(|| "".to_string())
|
||||
);
|
||||
remote_cloud_file_client.download_file(
|
||||
lora_details,
|
||||
path_to_string(lora_path.clone())
|
||||
).await?;
|
||||
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
}
|
||||
|
||||
// VAE token for now
|
||||
let vae_token = String::from("weight_rb0959wfzjhk3d1k93hr3s0qw");
|
||||
let model_weight_vae = ModelWeightToken(vae_token);
|
||||
|
||||
let vae_weight_record = get_weight_by_token(
|
||||
&model_weight_vae,
|
||||
false,
|
||||
&deps.db.mysql_pool
|
||||
).await?;
|
||||
|
||||
let vae_weight_record = match vae_weight_record {
|
||||
Some(val) => {
|
||||
val
|
||||
},
|
||||
None => {
|
||||
return Err(ProcessSingleJobError::from_anyhow_error(anyhow!("no VAE? thats a problem.")))
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
let vae_details = RemoteCloudBucketDetails::new(
|
||||
vae_weight_record.public_bucket_hash.clone(),
|
||||
vae_weight_record.maybe_public_bucket_prefix
|
||||
.clone()
|
||||
.unwrap_or_else(|| "".to_string()),
|
||||
vae_weight_record.maybe_public_bucket_extension
|
||||
.clone()
|
||||
.unwrap_or_else(|| "".to_string())
|
||||
);
|
||||
|
||||
remote_cloud_file_client.download_file(
|
||||
vae_details,
|
||||
path_to_string(vae_path.clone())
|
||||
).await?;
|
||||
|
||||
let prompt = match sd_args.maybe_prompt {
|
||||
Some(val) => {
|
||||
val
|
||||
}
|
||||
None => return Err(ProcessSingleJobError::from_anyhow_error(anyhow!("No Prompt provided!")))
|
||||
};
|
||||
|
||||
let stderr_output_file = work_temp_dir.path().join("sd_err.txt");
|
||||
|
||||
let number_of_samples = match sd_args.maybe_number_of_samples {
|
||||
Some(val) => {
|
||||
val
|
||||
},
|
||||
None => {
|
||||
20
|
||||
}
|
||||
};
|
||||
let inference_start_time = Instant::now();
|
||||
|
||||
sd_deps.inference_command.execute_inference(InferenceArgs {
|
||||
work_dir: work_temp_dir.path().to_path_buf(),
|
||||
output_file: output_path.clone(),
|
||||
stderr_output_file: stderr_output_file,
|
||||
prompt: prompt,
|
||||
negative_prompt:sd_args.maybe_n_prompt.unwrap_or_default(),
|
||||
number_of_samples: number_of_samples,
|
||||
samplers: sd_args.maybe_sampler.unwrap_or(String::from("Euler a")),
|
||||
width: sd_args.maybe_width.unwrap_or(512),
|
||||
height: sd_args.maybe_height.unwrap_or(512),
|
||||
cfg_scale: sd_args.maybe_cfg_scale.unwrap_or(7),
|
||||
seed: sd_args.maybe_seed.unwrap_or(1),
|
||||
lora_path: lora_path.clone(),
|
||||
checkpoint_path: sd_checkpoint_path.clone(),
|
||||
vae: vae_path.clone(),
|
||||
batch_count: sd_args.maybe_batch_count.unwrap_or(1),
|
||||
});
|
||||
|
||||
let inference_duration = Instant::now().duration_since(inference_start_time);
|
||||
let creator_ip_address = &job.creator_ip_address;
|
||||
// run a for loop for output images output_0 in the folder then use upload media.
|
||||
// pngs
|
||||
|
||||
if sd_args.type_of_inference == "inference" {
|
||||
// gather all the images into a single batch
|
||||
|
||||
|
||||
for i in 0..sd_args.maybe_batch_count.unwrap_or(1) {
|
||||
let path = output_path.clone();
|
||||
let file_path = format!("{}_{}.png", path_to_string(path), i);
|
||||
println!("Upload File Path:{}", file_path);
|
||||
let metadata = remote_cloud_file_client.upload_file(Box::new(MediaImagePngDescriptor {}), file_path.as_ref()).await?;
|
||||
|
||||
let bucket_details = match metadata.bucket_details {
|
||||
Some(val) => { val }
|
||||
None => return Err(ProcessSingleJobError::from_anyhow_error(anyhow!("no VAE? thats a problem.")))
|
||||
};
|
||||
|
||||
// TODO: Generic Insert with batch id.
|
||||
// insert media file generic should run here.
|
||||
insert_media_file_from_file_upload(InsertMediaFileFromUploadArgs {
|
||||
pool: mysql_pool,
|
||||
maybe_creator_user_token: Some(&creator_user_token),
|
||||
maybe_creator_anonymous_visitor_token: None,
|
||||
creator_ip_address: creator_ip_address,
|
||||
creator_set_visibility: Default::default(),
|
||||
upload_type: UploadType::Filesystem,
|
||||
media_file_type: MediaFileType::Image,
|
||||
maybe_mime_type: Some(metadata.mimetype.as_ref()),
|
||||
file_size_bytes: metadata.file_size_bytes,
|
||||
duration_millis: inference_duration.as_secs() * 1000,
|
||||
sha256_checksum: metadata.sha256_checksum.as_str(),
|
||||
public_bucket_directory_hash: bucket_details.object_hash.as_str(),
|
||||
maybe_public_bucket_prefix: Some(bucket_details.prefix.as_str()),
|
||||
maybe_public_bucket_extension: Some(bucket_details.suffix.as_str()),
|
||||
}).await?;
|
||||
}
|
||||
|
||||
// hack to check the directory before clean up.
|
||||
let thirtyMinutes = 1800;
|
||||
thread::sleep(Duration::from_secs(thirtyMinutes));
|
||||
// upload media and create a record.
|
||||
|
||||
Ok(JobSuccessResult {// TODO: batch token needs to go here
|
||||
maybe_result_entity: None,
|
||||
inference_duration: Duration::from_secs(0),
|
||||
})
|
||||
}
|
||||
else { // must be an upload and need upload token
|
||||
|
||||
|
||||
// The parameters will be updated on another screen perhaps?
|
||||
// so right now it will fill with the availible values.
|
||||
create_weight(CreateModelWeightsArgs {
|
||||
token: &ModelWeightToken::generate(),
|
||||
weights_type: WeightsType::StableDiffusion15,
|
||||
weights_category: WeightsCategory::ImageGeneration,
|
||||
title: "".to_string(),
|
||||
maybe_description_markdown: None,
|
||||
maybe_description_rendered_html: None,
|
||||
creator_user_token: Some(&creator_user_token),
|
||||
creator_ip_address: creator_ip_address,
|
||||
creator_set_visibility: Default::default(),
|
||||
maybe_last_update_user_token: None,
|
||||
original_download_url: None,
|
||||
original_filename: None,
|
||||
file_size_bytes: 0,
|
||||
file_checksum_sha2: "".to_string(),
|
||||
public_bucket_hash: "".to_string(),
|
||||
maybe_public_bucket_prefix: None,
|
||||
maybe_public_bucket_extension: None,
|
||||
version: 0,
|
||||
mysql_pool,
|
||||
}).await?;
|
||||
|
||||
Ok(JobSuccessResult {// TODO: batch token needs to go here
|
||||
maybe_result_entity: None,
|
||||
inference_duration: Duration::from_secs(0),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use anyhow::anyhow;
|
||||
use std::path::PathBuf;
|
||||
use cloud_storage::remote_file_manager::{
|
||||
remote_cloud_file_manager::{RemoteCloudFileClient, self},
|
||||
remote_cloud_bucket_details::RemoteCloudBucketDetails,
|
||||
};
|
||||
use errors::{AnyhowError, AnyhowResult};
|
||||
#[tokio::test]
|
||||
async fn test_seed_weights_files() -> AnyhowResult<()> {
|
||||
let seed_path = PathBuf::from("/storyteller/root/custom-seed-tool-data");
|
||||
let remote_cloud_file_client = RemoteCloudFileClient::get_remote_cloud_file_client().await;
|
||||
let remote_cloud_file_client = match remote_cloud_file_client {
|
||||
Ok(res) => {
|
||||
res
|
||||
}
|
||||
Err(_) => {
|
||||
return Err(anyhow!("failed to get remote cloud file client"));
|
||||
}
|
||||
};
|
||||
|
||||
let mut path_dl1 = seed_path.clone();
|
||||
path_dl1.push("downloads/loRA");
|
||||
let mut path_dl2 = seed_path.clone();
|
||||
path_dl2.push("downloads/checkpoint");
|
||||
|
||||
let bucket_details1 = RemoteCloudBucketDetails {
|
||||
object_hash: String::from("apa0ej6es8d3ss2gwtf1cghge35qn9tn"),
|
||||
prefix: String::from("sd15"),
|
||||
suffix: String::from("safetensors"),
|
||||
};
|
||||
|
||||
let bucket_details2 = RemoteCloudBucketDetails {
|
||||
object_hash: String::from("27kz11et18fargyyxbj66ntfn621k9d3"),
|
||||
prefix: String::from("loRA"),
|
||||
suffix: String::from("safetensors"),
|
||||
};
|
||||
|
||||
remote_cloud_file_client.download_file(bucket_details1, String::from("./checkpoint")).await?;
|
||||
remote_cloud_file_client.download_file(bucket_details2, String::from("./loRA")).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
+309
@@ -0,0 +1,309 @@
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::env;
|
||||
use std::ffi::OsString;
|
||||
use std::fs::File;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::anyhow;
|
||||
use log::info;
|
||||
use once_cell::sync::Lazy;
|
||||
use subprocess::{Popen, PopenConfig, Redirection};
|
||||
|
||||
use errors::AnyhowResult;
|
||||
use filesys::path_to_string::path_to_string;
|
||||
use subprocess_common::docker_options::{DockerFilesystemMount, DockerGpu, DockerOptions};
|
||||
|
||||
use crate::job::job_loop::command_exit_status::CommandExitStatus;
|
||||
|
||||
// These environment vars are not copied over to the subprocess
|
||||
// TODO/FIXME(bt, 2023-05-28): This is horrific security!
|
||||
static IGNORED_ENVIRONMENT_VARS : Lazy<HashSet<String>> = Lazy::new(|| {
|
||||
let env_var_names= [
|
||||
"MYSQL_URL",
|
||||
"ACCESS_KEY",
|
||||
"SECRET_KEY",
|
||||
"NEWRELIC_API_KEY",
|
||||
];
|
||||
|
||||
env_var_names.iter()
|
||||
.map(|value| value.to_string())
|
||||
.collect::<HashSet<String>>()
|
||||
});
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct StableDiffusionInferenceCommand {
|
||||
/// Where the code lives
|
||||
stable_diffusion_root_code_directory: PathBuf,
|
||||
|
||||
/// A single executable script or a much larger bash command.
|
||||
executable_or_command: ExecutableOrCommand,
|
||||
|
||||
/// eg. `source python/bin/activate`
|
||||
maybe_virtual_env_activation_command: Option<String>,
|
||||
|
||||
/// Optional default config file to use
|
||||
maybe_default_config_path: Option<PathBuf>,
|
||||
|
||||
/// If this is run under Docker (eg. in development), these are the options.
|
||||
maybe_docker_options: Option<DockerOptions>,
|
||||
|
||||
/// If the execution should be ended after a certain point.
|
||||
maybe_execution_timeout: Option<Duration>,
|
||||
|
||||
/// Inference arg.
|
||||
/// --checkpoint_dir: optional location for checkpoints directory
|
||||
pub alternate_checkpoint_dir: Option<PathBuf>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum ExecutableOrCommand {
|
||||
/// Eg. `inference.py`
|
||||
Executable(PathBuf),
|
||||
|
||||
/// Eg. `python3 inference.py`
|
||||
Command(String),
|
||||
}
|
||||
|
||||
pub struct InferenceArgs {
|
||||
/// --source_image: path to the input image (or video)
|
||||
/// --result_dir: path to directory work is performed
|
||||
pub work_dir: PathBuf,
|
||||
/// --result_file: path to final file output
|
||||
pub output_file: PathBuf,
|
||||
pub stderr_output_file: PathBuf,
|
||||
pub prompt: String,
|
||||
pub negative_prompt:String,
|
||||
pub number_of_samples:i32,
|
||||
pub samplers:String,
|
||||
pub width:i32,
|
||||
pub height:i32,
|
||||
pub cfg_scale:i32,
|
||||
pub seed:i64,
|
||||
pub lora_path:PathBuf,
|
||||
pub checkpoint_path:PathBuf,
|
||||
pub vae:PathBuf,
|
||||
pub batch_count:i32,
|
||||
}
|
||||
|
||||
impl StableDiffusionInferenceCommand {
|
||||
pub fn new<P: AsRef<Path>>(
|
||||
stable_diffusion_root_code_directory: P,
|
||||
executable_or_command: ExecutableOrCommand,
|
||||
maybe_virtual_env_activation_command: Option<&str>,
|
||||
maybe_default_config_path: Option<P>,
|
||||
maybe_docker_options: Option<DockerOptions>,
|
||||
maybe_execution_timeout: Option<Duration>,
|
||||
alternate_checkpoint_dir: Option<PathBuf>
|
||||
) -> Self {
|
||||
Self {
|
||||
stable_diffusion_root_code_directory: stable_diffusion_root_code_directory.as_ref().to_path_buf(),
|
||||
executable_or_command,
|
||||
maybe_virtual_env_activation_command: maybe_virtual_env_activation_command.map(|s| s.to_string()),
|
||||
maybe_default_config_path: maybe_default_config_path.map(|p| p.as_ref().to_path_buf()),
|
||||
maybe_docker_options,
|
||||
maybe_execution_timeout,
|
||||
alternate_checkpoint_dir,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_env() -> AnyhowResult<Self> {
|
||||
let stable_diffusion_root_code_directory = easyenv::get_env_pathbuf_required(
|
||||
"STABLE_DIFFUSION_INFERENCE_ROOT_DIRECTORY")?;
|
||||
|
||||
let maybe_inference_command = easyenv::get_env_string_optional(
|
||||
"STABLE_DIFFUSION_INFERENCE_COMMAND");
|
||||
|
||||
|
||||
let executable_or_command = match maybe_inference_command {
|
||||
Some(command) => ExecutableOrCommand::Command(command),
|
||||
None => {
|
||||
return Err(anyhow!("neither command nor executable passed"));
|
||||
}
|
||||
};
|
||||
|
||||
let maybe_virtual_env_activation_command = easyenv::get_env_string_optional(
|
||||
"STABLE_DIFFUSION_INFERENCE_MAYBE_VENV_COMMAND");
|
||||
|
||||
let maybe_default_config_path = easyenv::get_env_pathbuf_optional(
|
||||
"STABLE_DIFFUSION_INFERENCE_MAYBE_DEFAULT_CONFIG_PATH");
|
||||
|
||||
let maybe_execution_timeout: Option<Duration> =
|
||||
easyenv::get_env_duration_seconds_optional("STABLE_DIFFUSION_TIMEOUT_SECONDS");
|
||||
|
||||
let maybe_docker_options = easyenv::get_env_string_optional(
|
||||
"STABLE_DIFFUSION_INFERENCE_MAYBE_DOCKER_IMAGE")
|
||||
.map(|image_name| {
|
||||
DockerOptions {
|
||||
image_name,
|
||||
maybe_bind_mount: Some(DockerFilesystemMount::tmp_to_tmp()),
|
||||
maybe_environment_variables: None,
|
||||
maybe_gpu: Some(DockerGpu::All),
|
||||
}
|
||||
});
|
||||
|
||||
// Override for --checkpoint_dir at inference time
|
||||
let alternate_checkpoint_dir = easyenv::get_env_pathbuf_optional(
|
||||
"STABLE_DIFFUSION_ALTERNATE_CHECKPOINT_PATH");
|
||||
|
||||
Ok(Self {
|
||||
stable_diffusion_root_code_directory,
|
||||
executable_or_command,
|
||||
maybe_virtual_env_activation_command,
|
||||
maybe_default_config_path,
|
||||
maybe_docker_options,
|
||||
maybe_execution_timeout,
|
||||
alternate_checkpoint_dir,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn execute_inference(
|
||||
&self,
|
||||
args: InferenceArgs,
|
||||
) -> CommandExitStatus {
|
||||
match self.do_execute_inference(args) {
|
||||
Ok(exit_status) => exit_status,
|
||||
Err(error) => CommandExitStatus::FailureWithReason { reason: format!("error: {:?}", error) },
|
||||
}
|
||||
}
|
||||
|
||||
fn do_execute_inference(
|
||||
&self,
|
||||
args: InferenceArgs,
|
||||
) -> AnyhowResult<CommandExitStatus> {
|
||||
|
||||
let mut command = String::new();
|
||||
command.push_str(&format!("cd {}", path_to_string(&self.stable_diffusion_root_code_directory)));
|
||||
|
||||
if let Some(venv_command) = self.maybe_virtual_env_activation_command.as_deref() {
|
||||
command.push_str(" && ");
|
||||
command.push_str(venv_command);
|
||||
command.push_str(" ");
|
||||
}
|
||||
|
||||
command.push_str(" && ");
|
||||
|
||||
match self.executable_or_command {
|
||||
ExecutableOrCommand::Executable(ref executable) => {
|
||||
command.push_str(&path_to_string(executable));
|
||||
command.push_str(" ");
|
||||
}
|
||||
ExecutableOrCommand::Command(ref cmd) => {
|
||||
command.push_str(cmd);
|
||||
command.push_str(" ");
|
||||
}
|
||||
}
|
||||
|
||||
// ===== Begin Python Args =====
|
||||
command.push_str(format!("--prompt \"{}\"",&path_to_string(args.prompt)).as_ref());
|
||||
|
||||
command.push_str(" --output-dir ");
|
||||
command.push_str(&path_to_string(args.work_dir));
|
||||
|
||||
command.push_str(" --output-name ");
|
||||
command.push_str(&path_to_string(args.output_file));
|
||||
|
||||
// command.push_str(" --stderr-output-file ");
|
||||
// command.push_str(&path_to_string(args.stderr_output_file.clone()));
|
||||
|
||||
command.push_str(format!(" --negative-prompt \"{}\"",&path_to_string(args.negative_prompt)).as_ref());
|
||||
//command.push_str(&path_to_string(args.negative_prompt));
|
||||
|
||||
command.push_str(" --number-of-samples ");
|
||||
command.push_str(args.number_of_samples.to_string().as_str());
|
||||
|
||||
command.push_str(format!(" --samplers \"{}\"",&path_to_string(args.samplers)).as_ref());
|
||||
//command.push_str(&path_to_string(args.samplers));
|
||||
|
||||
command.push_str(" --width ");
|
||||
command.push_str(args.width.to_string().as_str());
|
||||
|
||||
command.push_str(" --height ");
|
||||
command.push_str(args.height.to_string().as_str());
|
||||
|
||||
command.push_str(" --cfg-scale ");
|
||||
command.push_str(args.cfg_scale.to_string().as_str());
|
||||
|
||||
command.push_str(" --seed ");
|
||||
command.push_str(args.seed.to_string().as_str());
|
||||
|
||||
command.push_str(" --loRA-path ");
|
||||
command.push_str(&path_to_string(args.lora_path));
|
||||
|
||||
command.push_str(" --check-point ");
|
||||
command.push_str(&path_to_string(args.checkpoint_path));
|
||||
|
||||
command.push_str(" --vae ");
|
||||
command.push_str(&path_to_string(args.vae));
|
||||
|
||||
command.push_str(" --batch-count ");
|
||||
command.push_str(args.batch_count.to_string().as_str());
|
||||
|
||||
command.push_str(" --batch-size ");
|
||||
command.push_str(1.to_string().as_str());
|
||||
|
||||
|
||||
info!("Command: {:?}", command);
|
||||
|
||||
let command_parts = [
|
||||
"bash",
|
||||
"-c",
|
||||
&command
|
||||
];
|
||||
|
||||
let mut env_vars = Vec::new();
|
||||
|
||||
// Copy all environment variables from the parent process.
|
||||
// This is necessary to send all the kubernetes settings for Nvidia / CUDA.
|
||||
for (env_key, env_value) in env::vars() {
|
||||
if IGNORED_ENVIRONMENT_VARS.contains(&env_key) {
|
||||
continue;
|
||||
}
|
||||
env_vars.push((
|
||||
OsString::from(env_key),
|
||||
OsString::from(env_value),
|
||||
));
|
||||
}
|
||||
|
||||
let mut config = PopenConfig::default();
|
||||
|
||||
info!("stderr will be written to file: {}", path_to_string(args.stderr_output_file.clone()));
|
||||
|
||||
let stderr_file = File::create(&args.stderr_output_file)?;
|
||||
config.stderr = Redirection::File(stderr_file);
|
||||
|
||||
if !env_vars.is_empty() {
|
||||
config.env = Some(env_vars);
|
||||
}
|
||||
|
||||
let mut p = Popen::create(&command_parts, config)?;
|
||||
|
||||
info!("Subprocess PID: {:?}", p.pid());
|
||||
|
||||
match self.maybe_execution_timeout {
|
||||
None => {
|
||||
let exit_status = p.wait()?;
|
||||
info!("Subprocess exit status: {:?}", exit_status);
|
||||
Ok(CommandExitStatus::from_exit_status(exit_status))
|
||||
}
|
||||
Some(timeout) => {
|
||||
info!("Executing with timeout: {:?}", &timeout);
|
||||
let exit_status = p.wait_timeout(timeout.clone())?;
|
||||
|
||||
match exit_status {
|
||||
None => {
|
||||
// NB: If the program didn't successfully terminate, kill it.
|
||||
info!("Subprocess didn't end after timeout: {:?}; terminating...", &timeout);
|
||||
let _r = p.terminate()?;
|
||||
Ok(CommandExitStatus::Timeout)
|
||||
}
|
||||
Some(exit_status) => {
|
||||
info!("Subprocess timed wait exit status: {:?}", exit_status);
|
||||
Ok(CommandExitStatus::from_exit_status(exit_status))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
use anyhow::{Ok};
|
||||
use errors::AnyhowResult;
|
||||
|
||||
use crate::job::job_types::image_generation::sd::model_downloaders::StableDiffusionDownloaders;
|
||||
use crate::job::job_types::image_generation::sd::sd_inference_command::StableDiffusionInferenceCommand;
|
||||
|
||||
pub struct StableDiffusionDependencies {
|
||||
pub downloaders: StableDiffusionDownloaders,
|
||||
pub inference_command: StableDiffusionInferenceCommand,
|
||||
}
|
||||
|
||||
impl StableDiffusionDependencies {
|
||||
pub fn setup() -> AnyhowResult<Self> {
|
||||
Ok(Self {
|
||||
downloaders: StableDiffusionDownloaders::build_all_from_env(),
|
||||
inference_command: StableDiffusionInferenceCommand::from_env()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
use mysql_queries::payloads::generic_inference_args::image_generation_payload::StableDiffusionArgs;
|
||||
use crate::job::job_loop::process_single_job_error::ProcessSingleJobError;
|
||||
use anyhow::anyhow;
|
||||
use mysql_queries::payloads::generic_inference_args::generic_inference_args::PolymorphicInferenceArgs;
|
||||
use crate::job::job_types::image_generation::sd::process_job::StableDiffusionProcessArgs;
|
||||
|
||||
|
||||
pub async fn validate_inputs(args: StableDiffusionProcessArgs<'_>) -> Result<(), ProcessSingleJobError> {
|
||||
let inference_args = args.job.maybe_inference_args
|
||||
.as_ref()
|
||||
.map(|args| args.args.as_ref())
|
||||
.flatten();
|
||||
|
||||
let polymorphic_args = match inference_args {
|
||||
Some(args) => args,
|
||||
None => {
|
||||
return Err(ProcessSingleJobError::from_anyhow_error(anyhow!("no inference args for job!")));
|
||||
}
|
||||
};
|
||||
|
||||
let sd_args = match polymorphic_args {
|
||||
PolymorphicInferenceArgs::Ig(args) => args,
|
||||
_ => {
|
||||
return Err(ProcessSingleJobError::from_anyhow_error(anyhow!("wrong inner args for job!")));
|
||||
}
|
||||
};
|
||||
|
||||
let stable_diffusion_args: StableDiffusionArgs = StableDiffusionArgs::from(sd_args.clone());
|
||||
if stable_diffusion_args.type_of_inference == "checkpoint" {
|
||||
|
||||
} else if stable_diffusion_args.type_of_inference == "lora" {
|
||||
|
||||
} else if stable_diffusion_args.type_of_inference == "inference" {
|
||||
|
||||
} else {
|
||||
return Err(ProcessSingleJobError::from_anyhow_error(anyhow!("wrong inference type for job!")));
|
||||
}
|
||||
|
||||
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -2,4 +2,6 @@ pub mod lipsync;
|
||||
pub mod tts;
|
||||
pub mod vc;
|
||||
pub(crate) mod videofilter;
|
||||
pub(crate) mod mocap;
|
||||
pub mod image_generation;
|
||||
pub(crate) mod mocap;
|
||||
|
||||
+1
@@ -72,6 +72,7 @@ pub struct VallEXInferenceCommand {
|
||||
pub alternate_checkpoint_dir: Option<PathBuf>,
|
||||
}
|
||||
|
||||
|
||||
impl VallEXInferenceCommand {
|
||||
pub fn new<P: AsRef<Path>>(
|
||||
root_code_directory: P,
|
||||
|
||||
@@ -260,6 +260,7 @@ pub async fn process_job(args: RvcV2ProcessJobArgs<'_>) -> Result<JobSuccessResu
|
||||
PolymorphicInferenceArgs::La(_) => None,
|
||||
PolymorphicInferenceArgs::Vc { override_f0_method, .. } => *override_f0_method,
|
||||
PolymorphicInferenceArgs::Rr(_) => None,
|
||||
PolymorphicInferenceArgs::Ig(_) => None,
|
||||
PolymorphicInferenceArgs::Mc(_) => None,
|
||||
})
|
||||
.flatten();
|
||||
@@ -270,6 +271,7 @@ pub async fn process_job(args: RvcV2ProcessJobArgs<'_>) -> Result<JobSuccessResu
|
||||
PolymorphicInferenceArgs::La(_) => None,
|
||||
PolymorphicInferenceArgs::Vc { transpose, .. } => *transpose,
|
||||
PolymorphicInferenceArgs::Rr(_) => None,
|
||||
PolymorphicInferenceArgs::Ig(_) => None,
|
||||
PolymorphicInferenceArgs::Mc(_) => None,
|
||||
})
|
||||
.flatten();
|
||||
|
||||
@@ -180,6 +180,7 @@ pub async fn process_job(args: SoVitsSvcProcessJobArgs<'_>) -> Result<JobSuccess
|
||||
PolymorphicInferenceArgs::La(_) => None,
|
||||
PolymorphicInferenceArgs::Vc { auto_predict_f0, .. } => *auto_predict_f0,
|
||||
PolymorphicInferenceArgs::Rr(_) => None,
|
||||
PolymorphicInferenceArgs::Ig(_) => None,
|
||||
PolymorphicInferenceArgs::Mc(_) => None,
|
||||
})
|
||||
.flatten()
|
||||
@@ -191,6 +192,7 @@ pub async fn process_job(args: SoVitsSvcProcessJobArgs<'_>) -> Result<JobSuccess
|
||||
PolymorphicInferenceArgs::La(_) => None,
|
||||
PolymorphicInferenceArgs::Vc { transpose, .. } => *transpose,
|
||||
PolymorphicInferenceArgs::Rr(_) => None,
|
||||
PolymorphicInferenceArgs::Ig(_) => None,
|
||||
PolymorphicInferenceArgs::Mc(_) => None,
|
||||
})
|
||||
.flatten();
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ use crate::util::scoped_temp_dir_creator::ScopedTempDirCreator;
|
||||
pub struct ModelFile {
|
||||
pub filesystem_path: PathBuf,
|
||||
}
|
||||
|
||||
// TODO replace this with remote cloud file manager.
|
||||
pub async fn download_model_file(
|
||||
model_record: &Option<RetrievedModelWeight>,
|
||||
public_bucket_client: &BucketClient,
|
||||
|
||||
+17
-17
@@ -22,7 +22,7 @@ use crate::util::scoped_temp_dir_creator::ScopedTempDirCreator;
|
||||
pub struct VideoFile {
|
||||
pub filesystem_path: PathBuf,
|
||||
}
|
||||
|
||||
// TODO replace this with remote cloud file manager.
|
||||
pub async fn download_video_file(
|
||||
video_source: &VideofilterVideoSource,
|
||||
public_bucket_client: &BucketClient,
|
||||
@@ -63,23 +63,23 @@ pub async fn download_video_file(
|
||||
}
|
||||
}
|
||||
}
|
||||
VideofilterVideoSource::U(media_upload_token) => {
|
||||
let media_upload_token = MediaUploadToken::new_from_str(media_upload_token);
|
||||
let media_upload_result = get_media_upload_for_inference(
|
||||
&media_upload_token,
|
||||
mysql_pool
|
||||
).await;
|
||||
VideofilterVideoSource::U(media_upload_token) => {
|
||||
let media_upload_token = MediaUploadToken::new_from_str(media_upload_token);
|
||||
let media_upload_result = get_media_upload_for_inference(
|
||||
&media_upload_token,
|
||||
mysql_pool
|
||||
).await;
|
||||
|
||||
let media_upload_result = match media_upload_result {
|
||||
Ok(Some(result)) => result,
|
||||
Ok(None) => {
|
||||
warn!("could not find media upload: {:?}", media_upload_token);
|
||||
return Err(ProcessSingleJobError::from_anyhow_error(
|
||||
anyhow!("could not find media upload: {:?}", media_upload_token)))
|
||||
}
|
||||
Err(e) => {
|
||||
error!("could not query media upload: {:?}", e);
|
||||
return Err(ProcessSingleJobError::from_anyhow_error(e))
|
||||
let media_upload_result = match media_upload_result {
|
||||
Ok(Some(result)) => result,
|
||||
Ok(None) => {
|
||||
warn!("could not find media upload: {:?}", media_upload_token);
|
||||
return Err(ProcessSingleJobError::from_anyhow_error(
|
||||
anyhow!("could not find media upload: {:?}", media_upload_token)))
|
||||
}
|
||||
Err(e) => {
|
||||
error!("could not query media upload: {:?}", e);
|
||||
return Err(ProcessSingleJobError::from_anyhow_error(e))
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
-1
@@ -35,7 +35,6 @@ const BUCKET_FILE_EXTENSION: &str = ".mp4";
|
||||
pub struct RerenderProcessJobArgs<'a> {
|
||||
pub job_dependencies: &'a JobDependencies,
|
||||
pub job: &'a AvailableInferenceJob,
|
||||
// pub media_file: MediaFile,
|
||||
}
|
||||
|
||||
pub async fn process_job(args: RerenderProcessJobArgs<'_>) -> Result<JobSuccessResult, ProcessSingleJobError> {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use enums::by_table::generic_inference_jobs::inference_model_type::InferenceModelType;
|
||||
use errors::AnyhowResult;
|
||||
use sqlx::pool::maybe;
|
||||
|
||||
use crate::job::job_types::lipsync::sad_talker::sad_talker_dependencies::SadTalkerDependencies;
|
||||
use crate::job::job_types::tts::styletts2::styletts2_dependencies::StyleTTS2Dependencies;
|
||||
@@ -9,6 +10,8 @@ use crate::job::job_types::tts::vits::vits_dependencies::VitsDependencies;
|
||||
use crate::job::job_types::vc::rvc_v2::rvc_v2_dependencies::RvcV2Dependencies;
|
||||
use crate::job::job_types::vc::so_vits_svc::svc_dependencies::SvcDependencies;
|
||||
use crate::job::job_types::videofilter::rerender_a_video::rerender_dependencies::RerenderDependencies;
|
||||
use crate::job::job_types::image_generation::sd::stable_diffusion_dependencies::StableDiffusionDependencies;
|
||||
|
||||
use crate::job::job_types::mocap::mocap_net::mocapnet_dependencies::MocapNetDependencies;
|
||||
use crate::util::scoped_execution::ScopedExecution;
|
||||
|
||||
@@ -20,6 +23,7 @@ pub struct JobSpecificDependencies {
|
||||
pub maybe_vall_e_x_dependencies: Option<VallExDependencies>,
|
||||
pub maybe_vits_dependencies: Option<VitsDependencies>,
|
||||
pub maybe_rerender_dependencies: Option<RerenderDependencies>,
|
||||
pub maybe_stable_diffusion_dependencies: Option<StableDiffusionDependencies>,
|
||||
pub maybe_mocapnet_dependencies: Option<MocapNetDependencies>,
|
||||
pub maybe_styletts2_dependencies: Option<StyleTTS2Dependencies>,
|
||||
}
|
||||
@@ -34,6 +38,7 @@ impl JobSpecificDependencies {
|
||||
let mut maybe_vall_e_x_dependencies = None;
|
||||
let mut maybe_vits_dependencies = None;
|
||||
let mut maybe_rerender_dependencies = None;
|
||||
let mut maybe_stable_diffusion_dependencies = None;
|
||||
let mut maybe_mocapnet_dependencies = None;
|
||||
let mut maybe_styletts2_dependencies = None;
|
||||
|
||||
@@ -76,6 +81,11 @@ impl JobSpecificDependencies {
|
||||
print_with_space("Setting Rerender dependencies...");
|
||||
maybe_rerender_dependencies = Some(RerenderDependencies::setup()?);
|
||||
}
|
||||
|
||||
if scoped_execution.can_run_job(InferenceModelType::StableDiffusion) {
|
||||
print_with_space("Setting Stable Diffusion dependencies...");
|
||||
maybe_stable_diffusion_dependencies = Some(StableDiffusionDependencies::setup()?);
|
||||
}
|
||||
|
||||
if scoped_execution.can_run_job(InferenceModelType::MocapNet) {
|
||||
print_with_space("Setting MocapNet dependencies...");
|
||||
@@ -90,6 +100,7 @@ impl JobSpecificDependencies {
|
||||
maybe_vall_e_x_dependencies,
|
||||
maybe_vits_dependencies,
|
||||
maybe_rerender_dependencies,
|
||||
maybe_stable_diffusion_dependencies,
|
||||
maybe_mocapnet_dependencies,
|
||||
maybe_styletts2_dependencies,
|
||||
})
|
||||
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
#[cfg(test)]
|
||||
use strum::EnumCount;
|
||||
#[cfg(test)]
|
||||
use strum::EnumIter;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize, ToSchema)]
|
||||
pub enum EnqueueImageGenType {
|
||||
#[serde(rename = "upload_lora")]
|
||||
UploadLoRA,
|
||||
#[serde(rename = "upload_sd")]
|
||||
Checkpoint,
|
||||
#[serde(rename = "inference")]
|
||||
Inference,
|
||||
}
|
||||
|
||||
impl EnqueueImageGenType {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::UploadLoRA => "upload_lora",
|
||||
Self::Checkpoint => "upload_sd",
|
||||
Self::Inference => "inference",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"upload_lora" => Ok(Self::UploadLoRA),
|
||||
"upload_sd" => Ok(Self::Checkpoint),
|
||||
"inference" => Ok(Self::Inference),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn all_variants() -> BTreeSet<Self> {
|
||||
BTreeSet::from([
|
||||
Self::UploadLoRA,
|
||||
Self::Checkpoint,
|
||||
Self::Inference
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_to_str() {
|
||||
assert_eq!(EnqueueImageGenType::UploadLoRA.to_str(), "upload_lora");
|
||||
assert_eq!(EnqueueImageGenType::Checkpoint.to_str(), "upload_sd");
|
||||
assert_eq!(EnqueueImageGenType::Inference.to_str(), "inference");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_str() {
|
||||
assert_eq!(EnqueueImageGenType::from_str("upload_lora").unwrap(), EnqueueImageGenType::UploadLoRA);
|
||||
assert_eq!(EnqueueImageGenType::from_str("upload_sd").unwrap(), EnqueueImageGenType::Checkpoint);
|
||||
assert_eq!(EnqueueImageGenType::from_str("inference").unwrap(), EnqueueImageGenType::Inference);
|
||||
assert!(EnqueueImageGenType::from_str("invalid").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_all_variants() {
|
||||
let variants = EnqueueImageGenType::all_variants();
|
||||
assert_eq!(variants.len(), 3);
|
||||
assert!(variants.contains(&EnqueueImageGenType::UploadLoRA));
|
||||
assert!(variants.contains(&EnqueueImageGenType::Checkpoint));
|
||||
assert!(variants.contains(&EnqueueImageGenType::Inference));
|
||||
}
|
||||
}
|
||||
+403
@@ -0,0 +1,403 @@
|
||||
// #![forbid(unused_imports)]
|
||||
#![forbid(unused_mut)]
|
||||
#![forbid(unused_variables)]
|
||||
|
||||
use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
|
||||
use actix_web::{HttpRequest, HttpResponse, web};
|
||||
use actix_web::error::ResponseError;
|
||||
use actix_web::http::StatusCode;
|
||||
use log::warn;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
use tokens::tokens::model_weights::ModelWeightToken;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
use enums::by_table::generic_inference_jobs::inference_category::InferenceCategory;
|
||||
use enums::by_table::generic_inference_jobs::inference_model_type::InferenceModelType;
|
||||
use http_server_common::request::get_request_header_optional::get_request_header_optional;
|
||||
use http_server_common::request::get_request_ip::get_request_ip;
|
||||
use mysql_queries::payloads::generic_inference_args::generic_inference_args::{
|
||||
GenericInferenceArgs,
|
||||
InferenceCategoryAbbreviated,
|
||||
PolymorphicInferenceArgs,
|
||||
};
|
||||
|
||||
use mysql_queries::payloads::generic_inference_args::image_generation_payload::StableDiffusionArgs;
|
||||
use mysql_queries::queries::generic_inference::web::insert_generic_inference_job::{
|
||||
insert_generic_inference_job,
|
||||
InsertGenericInferenceArgs,
|
||||
};
|
||||
|
||||
|
||||
use tokens::tokens::generic_inference_jobs::InferenceJobToken;
|
||||
use tokens::tokens::users::UserToken;
|
||||
|
||||
use crate::configs::plans::get_correct_plan_for_session::get_correct_plan_for_session;
|
||||
use crate::http_server::web_utils::response_error_helpers::to_simple_json_error;
|
||||
use crate::server_state::ServerState;
|
||||
|
||||
use std::fmt::{Display, Formatter};
|
||||
/// Debug requests can get routed to special "debug-only" workers, which can
|
||||
/// be used to trial new code, run debugging, etc.
|
||||
const DEBUG_HEADER_NAME: &str = "enable-debug-mode";
|
||||
|
||||
/// The routing tag header can send workloads to particular k8s hosts.
|
||||
/// This is useful for catching the live logs or intercepting the job.
|
||||
const ROUTING_TAG_HEADER_NAME: &str = "routing-tag";
|
||||
|
||||
#[derive(Debug,Deserialize, Clone, Copy, Eq, PartialEq)]
|
||||
pub enum TypeOfInference {
|
||||
#[serde(rename = "lora")]
|
||||
UploadLoRA,
|
||||
#[serde(rename = "checkpoint")]
|
||||
CheckPoint,
|
||||
#[serde(rename = "inference")]
|
||||
Inference,
|
||||
}
|
||||
impl Display for TypeOfInference {
|
||||
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
TypeOfInference::UploadLoRA => write!(f, "lora"),
|
||||
TypeOfInference::CheckPoint => write!(f, "checkpoint"),
|
||||
TypeOfInference::Inference => write!(f, "inference"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn is_valid_string(input: &str) -> bool {
|
||||
let valid_strings = [
|
||||
"DPM++ 2M Karras",
|
||||
"DPM++ SDE Karras",
|
||||
"DPM++ 2M SDE Exponential",
|
||||
"DPM++ 2M SDE Karras",
|
||||
"Euler a",
|
||||
"Euler",
|
||||
"LMS",
|
||||
"Heun",
|
||||
"DPM2",
|
||||
"DPM2 a",
|
||||
"DPM++ 2S a",
|
||||
"DPM++ 2M",
|
||||
"DPM++ SDE",
|
||||
"DPM++ 2M SDE",
|
||||
"DPM++ 2M SDE Heun",
|
||||
"DPM++ 2M SDE Heun Karras",
|
||||
"DPM++ 2M SDE Heun Exponential",
|
||||
"DPM++ 3M SDE",
|
||||
"DPM++ 3M SDE Karras",
|
||||
"DPM++ 3M SDE Exponential",
|
||||
"DPM fast",
|
||||
"DPM adaptive",
|
||||
"LMS Karras",
|
||||
"DPM2 Karras",
|
||||
"DPM2 a Karras",
|
||||
"DPM++ 2S a Karras"
|
||||
];
|
||||
valid_strings.contains(&input)
|
||||
}
|
||||
|
||||
|
||||
#[derive(Deserialize,ToSchema)]
|
||||
pub struct EnqueueImageGenRequest {
|
||||
uuid_idempotency_token: String,
|
||||
type_of_inference: TypeOfInference, // upload loRA / check point / standard inference
|
||||
maybe_image_source: Option<String>,
|
||||
maybe_sd_model_token: Option<String>,
|
||||
maybe_lora_model_token: Option<String>,
|
||||
maybe_prompt: Option<String>,
|
||||
maybe_n_prompt: Option<String>,
|
||||
maybe_seed: Option<i64>,
|
||||
maybe_width: Option<i32>,
|
||||
maybe_height: Option<i32>,
|
||||
maybe_sampler: Option<String>,
|
||||
maybe_upload_path: Option<String>,
|
||||
maybe_lora_upload_path: Option<String>,
|
||||
maybe_cfg_scale: Option<i32>,
|
||||
maybe_number_of_samples: Option<i32>,
|
||||
maybe_batch_count: Option<i32>,
|
||||
name: String,
|
||||
description: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize,ToSchema)]
|
||||
pub struct EnqueueImageGenRequestSuccessResponse {
|
||||
pub success: bool,
|
||||
pub inference_job_token: InferenceJobToken,
|
||||
}
|
||||
|
||||
#[derive(Debug,ToSchema)]
|
||||
pub enum EnqueueImageGenRequestError {
|
||||
BadInput(String),
|
||||
NotAuthorized,
|
||||
ServerError,
|
||||
RateLimited,
|
||||
}
|
||||
|
||||
impl ResponseError for EnqueueImageGenRequestError {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match *self {
|
||||
EnqueueImageGenRequestError::BadInput(_) => StatusCode::BAD_REQUEST,
|
||||
EnqueueImageGenRequestError::NotAuthorized => StatusCode::UNAUTHORIZED,
|
||||
EnqueueImageGenRequestError::ServerError => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
EnqueueImageGenRequestError::RateLimited => StatusCode::TOO_MANY_REQUESTS,
|
||||
}
|
||||
}
|
||||
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
let error_reason = match self {
|
||||
EnqueueImageGenRequestError::BadInput(reason) => reason.to_string(),
|
||||
EnqueueImageGenRequestError::NotAuthorized => "unauthorized".to_string(),
|
||||
EnqueueImageGenRequestError::ServerError => "server error".to_string(),
|
||||
EnqueueImageGenRequestError::RateLimited => "rate limited".to_string(),
|
||||
};
|
||||
|
||||
to_simple_json_error(&error_reason, self.status_code())
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for EnqueueImageGenRequestError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
// Implementation for enqueuing a TTS request
|
||||
// Reference enqueue_infer_tts_handler.rs for checks: rate limiting / user sessions
|
||||
// insert generic inference job.rs
|
||||
// Need to convert it to generic inference job.
|
||||
#[utoipa::path(
|
||||
post,
|
||||
path = "/inference/enqueue_image_gen/",
|
||||
responses(
|
||||
(status = 200, description = "Enqueue TTS generically", body = EnqueueImageGenRequestSuccessResponse),
|
||||
(status = 400, description = "Bad input", body = EnqueueImageGenRequestError),
|
||||
(status = 401, description = "Not authorized", body = EnqueueImageGenRequestError),
|
||||
(status = 429, description = "Rate limited", body = EnqueueImageGenRequestError),
|
||||
(status = 500, description = "Server error", body = EnqueueImageGenRequestError)
|
||||
),
|
||||
params(
|
||||
("request" = EnqueueImageGenRequest, description = "Payload for TTS Request")
|
||||
)
|
||||
)]
|
||||
pub async fn enqueue_image_generation_request(
|
||||
http_request: HttpRequest,
|
||||
request: web::Json<EnqueueImageGenRequest>,
|
||||
server_state: web::Data<Arc<ServerState>>
|
||||
) -> Result<HttpResponse, EnqueueImageGenRequestError> {
|
||||
|
||||
// TODO: Brandon need to figure out premium vs not premium
|
||||
|
||||
let mut maybe_user_token: Option<UserToken> = None;
|
||||
let visbility = enums::common::visibility::Visibility::Public;
|
||||
|
||||
let mut mysql_connection = server_state.mysql_pool.acquire().await.map_err(|err| {
|
||||
warn!("MySql pool error: {:?}", err);
|
||||
EnqueueImageGenRequestError::ServerError
|
||||
})?;
|
||||
|
||||
// ==================== USER SESSION ==================== //
|
||||
|
||||
let maybe_user_session = server_state.session_checker
|
||||
.maybe_get_user_session_extended_from_connection(&http_request, &mut mysql_connection).await
|
||||
.map_err(|e| {
|
||||
warn!("Session checker error: {:?}", e);
|
||||
EnqueueImageGenRequestError::ServerError
|
||||
})?;
|
||||
|
||||
|
||||
if let Some(user_session) = maybe_user_session.as_ref() {
|
||||
maybe_user_token = Some(UserToken::new_from_str(&user_session.user_token));
|
||||
}
|
||||
|
||||
// Plan should handle "first anonymous use" and "investor" cases.
|
||||
let plan = get_correct_plan_for_session(
|
||||
server_state.server_environment,
|
||||
maybe_user_session.as_ref()
|
||||
);
|
||||
|
||||
// Separate priority for animation.
|
||||
let priority_level = plan.web_vc_base_priority_level();
|
||||
|
||||
// ==================== DEBUG MODE + ROUTING TAG ==================== //
|
||||
|
||||
let is_debug_request = get_request_header_optional(&http_request, DEBUG_HEADER_NAME).is_some();
|
||||
|
||||
let maybe_routing_tag = get_request_header_optional(&http_request, ROUTING_TAG_HEADER_NAME).map(
|
||||
|routing_tag| routing_tag.trim().to_string()
|
||||
);
|
||||
|
||||
// ==================== BANNED USERS ==================== //
|
||||
|
||||
if let Some(ref user) = maybe_user_session {
|
||||
if user.role.is_banned {
|
||||
return Err(EnqueueImageGenRequestError::NotAuthorized);
|
||||
}
|
||||
}
|
||||
|
||||
// DETECT premium user and queue
|
||||
|
||||
// ==================== RATE LIMIT ==================== //
|
||||
|
||||
let rate_limiter = match maybe_user_session {
|
||||
None => &server_state.redis_rate_limiters.logged_out,
|
||||
Some(ref _user) => &server_state.redis_rate_limiters.logged_in,
|
||||
};
|
||||
|
||||
if let Err(_err) = rate_limiter.rate_limit_request(&http_request) {
|
||||
return Err(EnqueueImageGenRequestError::RateLimited);
|
||||
}
|
||||
|
||||
// Get up IP address
|
||||
let ip_address = get_request_ip(&http_request);
|
||||
|
||||
// Check the inference args to make sure everything is all there for upload loRA / model or standard inference
|
||||
|
||||
// ==================== INFERENCE ARGS ==================== //
|
||||
|
||||
if request.type_of_inference == TypeOfInference::Inference {
|
||||
if request.maybe_sd_model_token.is_none() {
|
||||
return Err(EnqueueImageGenRequestError::BadInput("No sd model token provided".to_string()));
|
||||
}
|
||||
|
||||
if request.maybe_prompt.is_none() {
|
||||
return Err(EnqueueImageGenRequestError::BadInput("No prompt provided".to_string()));
|
||||
}
|
||||
|
||||
} else if request.type_of_inference == TypeOfInference::UploadLoRA {
|
||||
if request.maybe_lora_upload_path.is_none() {
|
||||
return Err(EnqueueImageGenRequestError::BadInput("No lora upload path provided".to_string()));
|
||||
}
|
||||
} else if request.type_of_inference == TypeOfInference::CheckPoint {
|
||||
if request.maybe_upload_path.is_none() {
|
||||
return Err(EnqueueImageGenRequestError::BadInput("No upload path provided".to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
let width = request.maybe_width.unwrap_or(512);
|
||||
let height = request.maybe_height.unwrap_or(512);
|
||||
|
||||
let width = match width {
|
||||
0..=512 => 512,
|
||||
513..=768 => 768,
|
||||
769..=1024 => 1024,
|
||||
_ => 1024,
|
||||
};
|
||||
|
||||
let height = match height {
|
||||
0..=512 => 512,
|
||||
513..=768 => 768,
|
||||
769..=1024 => 1024,
|
||||
_ => 1024,
|
||||
};
|
||||
|
||||
let cfg_scale = match request.maybe_cfg_scale {
|
||||
Some(val) => if val > 32 { 32 } else { val },
|
||||
None => 7
|
||||
};
|
||||
|
||||
let number_of_samples = match request.maybe_number_of_samples {
|
||||
Some(val) => if val < 0 { 20 } else if val > 128 { 128 } else { val },
|
||||
None => 20,
|
||||
};
|
||||
|
||||
|
||||
let batch_count = match request.maybe_batch_count {
|
||||
Some(val) => if val > 4 { 4 } else { val },
|
||||
None => 1,
|
||||
};
|
||||
|
||||
let sampler = match request.maybe_sampler.clone() {
|
||||
Some(val) => if is_valid_string(&val) { val.clone() } else { String::from("Euler a") },
|
||||
None =>String::from( "Euler a"),
|
||||
};
|
||||
|
||||
let sd_weight_token = ModelWeightToken(request.maybe_sd_model_token.clone().unwrap_or_default());
|
||||
let lora_token = ModelWeightToken(request.maybe_lora_model_token.clone().unwrap_or_default());
|
||||
|
||||
|
||||
let n_prompt = request.maybe_n_prompt.clone().unwrap_or_default();
|
||||
|
||||
// we can only do 1 upload type at a time.
|
||||
// if we are uploading a model.
|
||||
let upload_path = request.maybe_upload_path.clone().unwrap_or_default();
|
||||
// if we are uploading a lora model.
|
||||
let lora_upload_path = request.maybe_lora_upload_path.clone().unwrap_or_default();
|
||||
|
||||
let mut seed = -1;
|
||||
|
||||
if let Some(s) = request.maybe_seed {
|
||||
seed = s;
|
||||
}
|
||||
|
||||
let type_of_inference = request.type_of_inference.to_string().clone();
|
||||
let description = request.description.to_string().clone();
|
||||
let name = request.name.to_string().clone();
|
||||
let inference_args = StableDiffusionArgs {
|
||||
maybe_sd_model_token: Some(sd_weight_token),
|
||||
maybe_lora_model_token: Some(lora_token),
|
||||
maybe_prompt: Some(request.maybe_prompt.clone().unwrap_or_default()),
|
||||
maybe_n_prompt: Some(n_prompt),
|
||||
maybe_seed: Some(seed),
|
||||
maybe_upload_path: Some(upload_path),
|
||||
maybe_lora_upload_path: Some(lora_upload_path),
|
||||
type_of_inference: type_of_inference,
|
||||
maybe_cfg_scale: Some(cfg_scale),
|
||||
maybe_number_of_samples: Some(number_of_samples),
|
||||
maybe_batch_count: Some(batch_count),
|
||||
maybe_width: Some(width),
|
||||
maybe_height: Some(height),
|
||||
maybe_sampler: Some(sampler),
|
||||
description: Some(description),
|
||||
name: Some(name),
|
||||
};
|
||||
|
||||
// create the inference args here
|
||||
let maybe_avt_token = server_state.avt_cookie_manager.get_avt_token_from_request(&http_request);
|
||||
|
||||
// create the job record here!
|
||||
let query_result = insert_generic_inference_job(InsertGenericInferenceArgs {
|
||||
uuid_idempotency_token: &request.uuid_idempotency_token,
|
||||
inference_category: InferenceCategory::ImageGeneration,
|
||||
maybe_model_type: Some(InferenceModelType::StableDiffusion), // NB: Model is static during inference
|
||||
maybe_model_token: None, // NB: Model is static during inference
|
||||
maybe_input_source_token: None,
|
||||
maybe_input_source_token_type: None,
|
||||
maybe_raw_inference_text: None,
|
||||
maybe_max_duration_seconds: None,
|
||||
maybe_inference_args: Some(GenericInferenceArgs {
|
||||
inference_category: Some(InferenceCategoryAbbreviated::ImageGeneration),
|
||||
args: Some(PolymorphicInferenceArgs::Ig(inference_args)),
|
||||
}),
|
||||
maybe_creator_user_token: maybe_user_token.as_ref(),
|
||||
maybe_avt_token: maybe_avt_token.as_ref(),
|
||||
creator_ip_address: &ip_address,
|
||||
creator_set_visibility: visbility,
|
||||
priority_level,
|
||||
requires_keepalive: true,
|
||||
is_debug_request,
|
||||
maybe_routing_tag: maybe_routing_tag.as_deref(),
|
||||
mysql_pool: &server_state.mysql_pool,
|
||||
}).await;
|
||||
|
||||
let job_token = match query_result {
|
||||
Ok((job_token, _id)) => job_token,
|
||||
Err(err) => {
|
||||
warn!("New generic inference job creation DB error: {:?}", err);
|
||||
return Err(EnqueueImageGenRequestError::ServerError);
|
||||
}
|
||||
};
|
||||
|
||||
let response: EnqueueImageGenRequestSuccessResponse = EnqueueImageGenRequestSuccessResponse {
|
||||
success: true,
|
||||
inference_job_token: job_token,
|
||||
};
|
||||
|
||||
let body = serde_json::to_string(&response).map_err(|_e| EnqueueImageGenRequestError::ServerError)?;
|
||||
|
||||
// Error handling 101 rust result type returned like so.
|
||||
Ok(HttpResponse::Ok().content_type("application/json").body(body))
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"uuid_idempotency_token": "123",
|
||||
"type_of_inference": "checkpoint",
|
||||
"maybe_sd_model_token": "weight_dmmthavhawqc2hj7yqyemcbf8",
|
||||
"maybe_lora_model_token": "weight_t7gz78fjg27m0wtw6r33gafxs",
|
||||
"maybe_prompt": "a very well drawn, anime girl, with pink and purple hair sitting down on a chair relaxed.",
|
||||
"maybe_a_prompt": "a anime girl, with pink and purple hair sitting down on a chair relaxed.",
|
||||
"maybe_n_prompt": "nsfw, black and white, low quality, pixelated",
|
||||
"maybe_seed": "-1",
|
||||
"maybe_width": "512",
|
||||
"maybe_height": "512",
|
||||
"maybe_sampler": "DPM++ 2M SDE Heun",
|
||||
"maybe_upload_path": "https://drive.google.com/file/d/1WRgR2pn0Ky8ls5_9Zq6tQlHTBvyWeach/view?usp=sharing",
|
||||
"maybe_lora_upload_path": "https://drive.google.com/file/d/1WRgR2pn0Ky8ls5_9Zq6tQlHTBvyWeach/view?usp=sharing",
|
||||
"maybe_cfg_scale": "7",
|
||||
"maybe_number_of_samples": "32",
|
||||
"maybe_batch_count": "4"
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
pub mod enqueue_image_generation;
|
||||
pub mod enqueue_generation_type;
|
||||
+4
-1
@@ -310,8 +310,11 @@ fn record_to_payload(
|
||||
}
|
||||
}
|
||||
}
|
||||
InferenceCategory::ImageGeneration => {
|
||||
"".to_string()
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
ResultDetailsResponse {
|
||||
entity_type: result_details.entity_type,
|
||||
entity_token: result_details.entity_token,
|
||||
|
||||
@@ -27,4 +27,5 @@ pub mod voice_designer;
|
||||
pub mod w2l;
|
||||
pub mod user_bookmarks;
|
||||
pub mod weights;
|
||||
pub(crate) mod mocap;
|
||||
pub mod image_gen;
|
||||
pub(crate) mod mocap;
|
||||
|
||||
@@ -166,6 +166,7 @@ use crate::http_server::endpoints::weights::list_weights_by_user::list_weights_b
|
||||
use crate::http_server::endpoints::weights::search_model_weights_handler::search_model_weights_handler;
|
||||
use crate::http_server::endpoints::weights::set_model_weight_cover_image::set_model_weight_cover_image_handler;
|
||||
use crate::http_server::endpoints::weights::update_weight::update_weight_handler;
|
||||
use crate::http_server::endpoints::image_gen::enqueue_image_generation::enqueue_image_generation_request;
|
||||
|
||||
pub fn add_routes<T, B> (app: App<T>, server_environment: ServerEnvironment) -> App<T>
|
||||
where
|
||||
@@ -198,12 +199,11 @@ pub fn add_routes<T, B> (app: App<T>, server_environment: ServerEnvironment) ->
|
||||
app = add_user_rating_routes(app); /* /v1/user_rating/... */
|
||||
app = add_subscription_routes(app); /* /v1/subscriptions/... */
|
||||
app = add_voice_designer_routes(app); /* /v1/voice_designer */
|
||||
app = add_weights_routes(app); /* /v1/weights/... */
|
||||
|
||||
//if server_environment == ServerEnvironment::Development {
|
||||
// // ...
|
||||
//}
|
||||
|
||||
app = add_image_gen_routes(app);
|
||||
app = add_weights_routes(app);
|
||||
// if server_environment == ServerEnvironment::Development {
|
||||
//
|
||||
// }
|
||||
// ==================== Comments ====================
|
||||
|
||||
let mut app = RouteBuilder::from_app(app)
|
||||
@@ -223,6 +223,7 @@ pub fn add_routes<T, B> (app: App<T>, server_environment: ServerEnvironment) ->
|
||||
.add_get("/v1/user_bookmarks/list/entity/{entity_type}/{entity_token}", list_user_bookmarks_for_entity_handler)
|
||||
.into_app();
|
||||
|
||||
|
||||
// ==================== Animations ====================
|
||||
|
||||
let mut app = RouteBuilder::from_app(app)
|
||||
@@ -1273,6 +1274,32 @@ fn add_voice_designer_routes<T,B> (app:App<T>)-> App<T>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
fn add_image_gen_routes<T,B> (app:App<T>)-> App<T>
|
||||
where
|
||||
B: MessageBody,
|
||||
T: ServiceFactory<
|
||||
ServiceRequest,
|
||||
Config = (),
|
||||
Response = ServiceResponse<B>,
|
||||
Error = Error,
|
||||
InitError = (),
|
||||
>,
|
||||
{
|
||||
//
|
||||
app.service(
|
||||
web::scope("/v1/image_gen")
|
||||
.service(
|
||||
web::scope("/model")
|
||||
.route("/upload", web::post().to(enqueue_image_generation_request))
|
||||
)
|
||||
.service(
|
||||
web::scope("/inference")
|
||||
.route("/enqueue_image_gen", web::post().to(enqueue_image_generation_request))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// ==================== Weights ROUTES ====================
|
||||
fn add_weights_routes<T, B>(app: App<T>) -> App<T>
|
||||
where
|
||||
|
||||
Reference in New Issue
Block a user