mirror of
https://github.com/storytold/artcraft.git
synced 2026-10-25 19:29:29 -04:00
Compare commits
24
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d39962491f | ||
|
|
eedbc346fe | ||
|
|
7976f68fd0 | ||
|
|
8a6678c7f5 | ||
|
|
d9b1c8c36b | ||
|
|
fc122cb996 | ||
|
|
e0e85fed5f | ||
|
|
092745166e | ||
|
|
ea859bfc1e | ||
|
|
92e0b1e9f4 | ||
|
|
d52d3f993a | ||
|
|
0033af73ce | ||
|
|
514f80b884 | ||
|
|
74c548c02f | ||
|
|
5fe09a182f | ||
|
|
4856ac28aa | ||
|
|
404853e129 | ||
|
|
b5fcc3cdfa | ||
|
|
300ac56ab7 | ||
|
|
e32f8094e5 | ||
|
|
e986a44e9d | ||
|
|
642e17a77d | ||
|
|
ac13be2900 | ||
|
|
b55435d992 |
Generated
+633
-213
File diff suppressed because it is too large
Load Diff
+3
-2
@@ -86,8 +86,9 @@ members = [
|
||||
"crates/service/plugins/users",
|
||||
|
||||
# Vendored code
|
||||
"crates/vendor/limitation",
|
||||
"crates/vendor/newrelic-telemetry-sdk-rust",
|
||||
|
||||
# Vendored code
|
||||
"my-workspace-hack",
|
||||
# cargo-hakari workspace hack (compilation speedup hack)
|
||||
"crates/my-workspace-hack",
|
||||
]
|
||||
|
||||
@@ -29,7 +29,9 @@ Web API Overview
|
||||
* `tts-inference-job` - (*deprecated*) Async TTS inference of Tacotron2 models only
|
||||
* `w2l-download-job` - (*deprecated*) Async download of videos and images
|
||||
* `w2l-inference-job` - (*deprecated*) Async W2L inference
|
||||
|
||||
* Documentation Server:
|
||||
* `docs` - this will run a local swagger server with the endpoints that you have access to, http://127.0.0.1:8989/api-docs/openapi.json use this to port everything over to the post man.
|
||||
|
||||
### PowerStream
|
||||
|
||||
* [PowerStream](https://power.stream) (deprecated) is powered by the following applications:
|
||||
|
||||
@@ -380,3 +380,16 @@ of this error message. You can essentially ignore it.
|
||||
### [Fix] Can't connect to local MySQL after install on Ubuntu
|
||||
|
||||
- If MySql in local dev can't be connected to, [reset the accounts](https://linuxconfig.org/how-to-reset-root-mysql-mariadb-password-on-ubuntu-20-04-focal-fossa-linux).
|
||||
|
||||
### API Server
|
||||
```
|
||||
cargo run --bin docs
|
||||
```
|
||||
This setups an api server with swagger docs to show you responses and requests with each associated endpoint
|
||||
It is run at http://127.0.0.1:8989/
|
||||
To obtain the json for the postman collection go to this url http://127.0.0.1:8989/api-docs/openapi.json
|
||||
We use this: `https://github.com/juhaku/utoipa`
|
||||
The documentation example is in:
|
||||
`crates/service/web/storyteller_web/src/http_server/endpoints/voice_designer/inference/enqueue_tts_request.rs`
|
||||
Write into the api doc to:
|
||||
`crates/service/web/storyteller_web/src/api_doc.rs`
|
||||
@@ -17,7 +17,7 @@ path = "src/lib.rs"
|
||||
# Internal
|
||||
crockford = { path = "../../lib/crockford" }
|
||||
errors = { path = "../../lib/errors" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
# External
|
||||
# (none yet)
|
||||
|
||||
@@ -17,14 +17,10 @@ path = "src/lib.rs"
|
||||
serde = "1.0.125"
|
||||
serde_derive = "1.0.125"
|
||||
|
||||
# MySql Database
|
||||
# "offline" supports typesafe builds without a live database
|
||||
# "rustls" doesn't appear to work with IP addresses, per:
|
||||
# https://github.com/launchbadge/sqlx/issues/1095#issuecomment-798050828
|
||||
sqlx = { version = "0.7.2", features = [ "mysql", "sqlite", "runtime-tokio-native-tls", "chrono" ] }
|
||||
sqlx-core = { version = "0.7.2" }
|
||||
sqlx-mysql= { version = "0.7.2" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
|
||||
@@ -13,10 +13,11 @@ use strum::EnumIter;
|
||||
///
|
||||
/// DO NOT CHANGE VALUES WITHOUT A MIGRATION STRATEGY.
|
||||
#[cfg_attr(test, derive(EnumIter, EnumCount))]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)]
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize, Default)]
|
||||
pub enum InferenceCategory {
|
||||
/// Eg. SadTalker and possibly Wav2Lip
|
||||
#[serde(rename = "lipsync_animation")]
|
||||
#[default]
|
||||
LipsyncAnimation,
|
||||
|
||||
#[serde(rename = "text_to_speech")]
|
||||
|
||||
@@ -21,6 +21,11 @@ pub enum IdCategory {
|
||||
#[serde(rename = "lipsync_animation")]
|
||||
LipsyncAnimationResult,
|
||||
|
||||
/// Results from tacotron2
|
||||
/// Applies for RVC and SVC
|
||||
#[serde(rename = "tts_result")]
|
||||
TtsResult,
|
||||
|
||||
/// Results from voice conversion (which may live in the media_files table)
|
||||
/// Applies for RVC and SVC
|
||||
#[serde(rename = "voice_conversion")]
|
||||
@@ -52,6 +57,7 @@ impl IdCategory {
|
||||
match self {
|
||||
Self::MediaFile => "media_file",
|
||||
Self::LipsyncAnimationResult => "lipsync_animation",
|
||||
Self::TtsResult => "tts_result",
|
||||
Self::VoiceConversionResult => "voice_conversion",
|
||||
Self::ZeroShotVoiceDataset => "zs_dataset",
|
||||
Self::ZeroShotVoiceEmbedding => "zs_voice",
|
||||
@@ -64,6 +70,7 @@ impl IdCategory {
|
||||
match value {
|
||||
"media_file" => Ok(Self::MediaFile),
|
||||
"lipsync_animation" => Ok(Self::LipsyncAnimationResult),
|
||||
"tts_result" => Ok(Self::TtsResult),
|
||||
"voice_conversion" => Ok(Self::VoiceConversionResult),
|
||||
"zs_dataset" => Ok(Self::ZeroShotVoiceDataset),
|
||||
"zs_voice" => Ok(Self::ZeroShotVoiceEmbedding),
|
||||
@@ -79,6 +86,7 @@ impl IdCategory {
|
||||
BTreeSet::from([
|
||||
Self::MediaFile,
|
||||
Self::LipsyncAnimationResult,
|
||||
Self::TtsResult,
|
||||
Self::VoiceConversionResult,
|
||||
Self::ZeroShotTtsResult,
|
||||
Self::ZeroShotVoiceDataset,
|
||||
@@ -100,6 +108,7 @@ mod tests {
|
||||
fn test_serialization() {
|
||||
assert_serialization(IdCategory::MediaFile, "media_file");
|
||||
assert_serialization(IdCategory::LipsyncAnimationResult, "lipsync_animation");
|
||||
assert_serialization(IdCategory::TtsResult, "tts_result");
|
||||
assert_serialization(IdCategory::VoiceConversionResult, "voice_conversion");
|
||||
assert_serialization(IdCategory::ZeroShotVoiceDataset, "zs_dataset");
|
||||
assert_serialization(IdCategory::ZeroShotVoiceEmbedding, "zs_voice");
|
||||
@@ -111,6 +120,7 @@ mod tests {
|
||||
fn to_str() {
|
||||
assert_eq!(IdCategory::MediaFile.to_str(), "media_file");
|
||||
assert_eq!(IdCategory::LipsyncAnimationResult.to_str(), "lipsync_animation");
|
||||
assert_eq!(IdCategory::TtsResult.to_str(), "tts_result");
|
||||
assert_eq!(IdCategory::VoiceConversionResult.to_str(), "voice_conversion");
|
||||
assert_eq!(IdCategory::ZeroShotVoiceDataset.to_str(), "zs_dataset");
|
||||
assert_eq!(IdCategory::ZeroShotVoiceEmbedding.to_str(), "zs_voice");
|
||||
@@ -122,6 +132,7 @@ mod tests {
|
||||
fn from_str() {
|
||||
assert_eq!(IdCategory::from_str("media_file").unwrap(), IdCategory::MediaFile);
|
||||
assert_eq!(IdCategory::from_str("lipsync_animation").unwrap(), IdCategory::LipsyncAnimationResult);
|
||||
assert_eq!(IdCategory::from_str("tts_result").unwrap(), IdCategory::TtsResult);
|
||||
assert_eq!(IdCategory::from_str("voice_conversion").unwrap(), IdCategory::VoiceConversionResult);
|
||||
assert_eq!(IdCategory::from_str("zs_dataset").unwrap(), IdCategory::ZeroShotVoiceDataset);
|
||||
assert_eq!(IdCategory::from_str("zs_voice").unwrap(), IdCategory::ZeroShotVoiceEmbedding);
|
||||
@@ -133,9 +144,10 @@ mod tests {
|
||||
fn all_variants() {
|
||||
// Static check
|
||||
let mut variants = IdCategory::all_variants();
|
||||
assert_eq!(variants.len(), 7);
|
||||
assert_eq!(variants.len(), 8);
|
||||
assert_eq!(variants.pop_first(), Some(IdCategory::MediaFile));
|
||||
assert_eq!(variants.pop_first(), Some(IdCategory::LipsyncAnimationResult));
|
||||
assert_eq!(variants.pop_first(), Some(IdCategory::TtsResult));
|
||||
assert_eq!(variants.pop_first(), Some(IdCategory::VoiceConversionResult));
|
||||
assert_eq!(variants.pop_first(), Some(IdCategory::ZeroShotTtsResult));
|
||||
assert_eq!(variants.pop_first(), Some(IdCategory::ZeroShotVoiceDataset));
|
||||
|
||||
@@ -25,6 +25,9 @@ pub enum MediaFileOriginModelType {
|
||||
#[serde(rename = "so_vits_svc")]
|
||||
SoVitsSvc,
|
||||
|
||||
#[serde(rename = "tacotron2")]
|
||||
Tacotron2,
|
||||
|
||||
#[serde(rename = "vall_e_x")]
|
||||
VallEX,
|
||||
}
|
||||
@@ -41,6 +44,7 @@ impl MediaFileOriginModelType {
|
||||
Self::RvcV2 => "rvc_v2",
|
||||
Self::SadTalker => "sad_talker",
|
||||
Self::SoVitsSvc => "so_vits_svc",
|
||||
Self::Tacotron2 => "tacotron2",
|
||||
Self::VallEX => "vall_e_x"
|
||||
}
|
||||
}
|
||||
@@ -50,6 +54,7 @@ impl MediaFileOriginModelType {
|
||||
"rvc_v2" => Ok(Self::RvcV2),
|
||||
"sad_talker" => Ok(Self::SadTalker),
|
||||
"so_vits_svc" => Ok(Self::SoVitsSvc),
|
||||
"tacotron2" => Ok(Self::Tacotron2),
|
||||
"vall_e_x" => Ok(Self::VallEX),
|
||||
_ => Err(format!("invalid value: {:?}", value)),
|
||||
}
|
||||
@@ -62,6 +67,7 @@ impl MediaFileOriginModelType {
|
||||
Self::RvcV2,
|
||||
Self::SadTalker,
|
||||
Self::SoVitsSvc,
|
||||
Self::Tacotron2,
|
||||
Self::VallEX
|
||||
])
|
||||
}
|
||||
@@ -85,6 +91,7 @@ mod tests {
|
||||
assert_eq!(MediaFileOriginModelType::RvcV2.to_str(), "rvc_v2");
|
||||
assert_eq!(MediaFileOriginModelType::SadTalker.to_str(), "sad_talker");
|
||||
assert_eq!(MediaFileOriginModelType::SoVitsSvc.to_str(), "so_vits_svc");
|
||||
assert_eq!(MediaFileOriginModelType::Tacotron2.to_str(), "tacotron2");
|
||||
assert_eq!(MediaFileOriginModelType::VallEX.to_str(), "vall_e_x");
|
||||
}
|
||||
|
||||
@@ -93,17 +100,19 @@ mod tests {
|
||||
assert_eq!(MediaFileOriginModelType::from_str("rvc_v2").unwrap(), MediaFileOriginModelType::RvcV2);
|
||||
assert_eq!(MediaFileOriginModelType::from_str("sad_talker").unwrap(), MediaFileOriginModelType::SadTalker);
|
||||
assert_eq!(MediaFileOriginModelType::from_str("so_vits_svc").unwrap(), MediaFileOriginModelType::SoVitsSvc);
|
||||
assert_eq!(MediaFileOriginModelType::from_str("tacotron2").unwrap(), MediaFileOriginModelType::Tacotron2);
|
||||
assert_eq!(MediaFileOriginModelType::from_str("vall_e_x").unwrap(), MediaFileOriginModelType::VallEX);
|
||||
assert!(MediaFileOriginModelType::from_str("foo").is_err());
|
||||
assert!(MediaFileOriginModelType::from_str("foo").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
let mut variants = MediaFileOriginModelType::all_variants();
|
||||
assert_eq!(variants.len(), 4);
|
||||
assert_eq!(variants.len(), 5);
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginModelType::RvcV2));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginModelType::SadTalker));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginModelType::SoVitsSvc));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginModelType::Tacotron2));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginModelType::VallEX));
|
||||
assert_eq!(variants.pop_first(), None);
|
||||
}
|
||||
|
||||
@@ -21,6 +21,10 @@ pub enum MediaFileOriginProductCategory {
|
||||
#[serde(rename = "face_animator")]
|
||||
FaceAnimator,
|
||||
|
||||
/// Text to speech (Tacotron2, not voice designer / VallE-X)
|
||||
#[serde(rename = "tts")]
|
||||
TextToSpeech,
|
||||
|
||||
// TODO: This should be a temporary category until we migrate the DB to remove this default value
|
||||
/// Unknown which product is attached to the file (generated the file, the file was
|
||||
/// uploaded on behalf of, etc.)
|
||||
@@ -46,6 +50,7 @@ impl MediaFileOriginProductCategory {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
Self::FaceAnimator => "face_animator",
|
||||
Self::TextToSpeech => "tts",
|
||||
Self::Unknown => "unknown",
|
||||
Self::VoiceConversion => "voice_conversion",
|
||||
Self::ZeroShotVoice => "zs_voice",
|
||||
@@ -55,6 +60,7 @@ impl MediaFileOriginProductCategory {
|
||||
pub fn from_str(value: &str) -> Result<Self, String> {
|
||||
match value {
|
||||
"face_animator" => Ok(Self::FaceAnimator),
|
||||
"tts" => Ok(Self::TextToSpeech),
|
||||
"unknown" => Ok(Self::Unknown),
|
||||
"voice_conversion" => Ok(Self::VoiceConversion),
|
||||
"zs_voice" => Ok(Self::ZeroShotVoice),
|
||||
@@ -67,6 +73,7 @@ impl MediaFileOriginProductCategory {
|
||||
// NB: BTreeSet::from() isn't const, but not worth using LazyStatic, etc.
|
||||
BTreeSet::from([
|
||||
Self::FaceAnimator,
|
||||
Self::TextToSpeech,
|
||||
Self::Unknown,
|
||||
Self::VoiceConversion,
|
||||
Self::ZeroShotVoice,
|
||||
@@ -85,6 +92,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(MediaFileOriginProductCategory::FaceAnimator, "face_animator");
|
||||
assert_serialization(MediaFileOriginProductCategory::TextToSpeech, "tts");
|
||||
assert_serialization(MediaFileOriginProductCategory::Unknown, "unknown");
|
||||
assert_serialization(MediaFileOriginProductCategory::VoiceConversion, "voice_conversion");
|
||||
assert_serialization(MediaFileOriginProductCategory::ZeroShotVoice, "zs_voice");
|
||||
@@ -93,6 +101,7 @@ mod tests {
|
||||
#[test]
|
||||
fn to_str() {
|
||||
assert_eq!(MediaFileOriginProductCategory::FaceAnimator.to_str(), "face_animator");
|
||||
assert_eq!(MediaFileOriginProductCategory::TextToSpeech.to_str(), "tts");
|
||||
assert_eq!(MediaFileOriginProductCategory::Unknown.to_str(), "unknown");
|
||||
assert_eq!(MediaFileOriginProductCategory::VoiceConversion.to_str(), "voice_conversion");
|
||||
assert_eq!(MediaFileOriginProductCategory::ZeroShotVoice.to_str(), "zs_voice");
|
||||
@@ -101,6 +110,7 @@ mod tests {
|
||||
#[test]
|
||||
fn from_str() {
|
||||
assert_eq!(MediaFileOriginProductCategory::from_str("face_animator").unwrap(), MediaFileOriginProductCategory::FaceAnimator);
|
||||
assert_eq!(MediaFileOriginProductCategory::from_str("tts").unwrap(), MediaFileOriginProductCategory::TextToSpeech);
|
||||
assert_eq!(MediaFileOriginProductCategory::from_str("unknown").unwrap(), MediaFileOriginProductCategory::Unknown);
|
||||
assert_eq!(MediaFileOriginProductCategory::from_str("voice_conversion").unwrap(), MediaFileOriginProductCategory::VoiceConversion);
|
||||
assert_eq!(MediaFileOriginProductCategory::from_str("zs_voice").unwrap(), MediaFileOriginProductCategory::ZeroShotVoice);
|
||||
@@ -109,8 +119,9 @@ mod tests {
|
||||
#[test]
|
||||
fn all_variants() {
|
||||
let mut variants = MediaFileOriginProductCategory::all_variants();
|
||||
assert_eq!(variants.len(), 4);
|
||||
assert_eq!(variants.len(), 5);
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::FaceAnimator));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::TextToSpeech));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::Unknown));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::VoiceConversion));
|
||||
assert_eq!(variants.pop_first(), Some(MediaFileOriginProductCategory::ZeroShotVoice));
|
||||
|
||||
@@ -34,6 +34,12 @@ impl_mysql_enum_coders!(JobStatusPlus);
|
||||
|
||||
// NB: We can derive `sqlx::Type` instead of using `impl_mysql_enum_coders`
|
||||
|
||||
impl Default for JobStatusPlus {
|
||||
fn default() -> Self {
|
||||
Self::Pending
|
||||
}
|
||||
}
|
||||
|
||||
impl JobStatusPlus {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
@@ -86,6 +92,11 @@ mod tests {
|
||||
mod explicit_checks {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_default() {
|
||||
assert_eq!(JobStatusPlus::default(), JobStatusPlus::Pending);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_serialization() {
|
||||
assert_serialization(JobStatusPlus::Pending, "pending");
|
||||
|
||||
@@ -18,7 +18,7 @@ path = "src/lib.rs"
|
||||
# (none)
|
||||
|
||||
# External
|
||||
chrono = { version = "=0.4.22", features = ["serde"] }
|
||||
chrono = { version = "0.4.22", features = ["serde"] }
|
||||
|
||||
# Serialization
|
||||
serde = "1.0.125"
|
||||
@@ -26,7 +26,7 @@ serde_derive = "1.0.125"
|
||||
|
||||
# MySql Database
|
||||
sqlx = { version = "0.7.2", features = [ "mysql", "runtime-tokio", "tls-rustls", "chrono" ] }
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
[dev-dependencies]
|
||||
# Test serialization
|
||||
|
||||
@@ -20,13 +20,11 @@ serde_derive = "1.0.125"
|
||||
# Random
|
||||
rand = "0.8.5"
|
||||
|
||||
# MySql Database
|
||||
# "offline" supports typesafe builds without a live database
|
||||
# "rustls" doesn't appear to work with IP addresses, per:
|
||||
# https://github.com/launchbadge/sqlx/issues/1095#issuecomment-798050828
|
||||
sqlx = { version = "0.7.2", features = [ "mysql", "runtime-tokio", "tls-rustls", "chrono" ] }
|
||||
sqlx-core = { version = "0.7.2" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
utoipa = { version = "4", features = ["actix_extras"] }
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ use crate::prefixes::TokenPrefix;
|
||||
/// A rare instance that is *not* a primary key.
|
||||
/// These are generated as cookies to track users for a better logged out experience and for analytics.
|
||||
/// We use these as indices into several columns (ML result types, uploads, etc.)
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, sqlx::Type, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, sqlx::Type, Debug, Serialize, Deserialize, Default)]
|
||||
#[sqlx(transparent)]
|
||||
pub struct AnonymousVisitorTrackingToken(pub String);
|
||||
|
||||
|
||||
@@ -4,9 +4,10 @@ use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::prefixes::TokenPrefix;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
/// The primary key for "generic" inference jobs.
|
||||
#[derive(Clone, PartialEq, Eq, sqlx::Type, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, PartialEq, Eq, sqlx::Type, Debug, Serialize, Deserialize, Default, ToSchema)]
|
||||
#[sqlx(transparent)]
|
||||
pub struct InferenceJobToken(String);
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ use serde::Serialize;
|
||||
use crate::prefixes::TokenPrefix;
|
||||
|
||||
/// The primary key for users.
|
||||
#[derive(Clone, PartialEq, Eq, sqlx::Type, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, PartialEq, Eq, sqlx::Type, Debug, Serialize, Deserialize, Default)]
|
||||
#[sqlx(transparent)]
|
||||
pub struct UserToken(pub String);
|
||||
|
||||
|
||||
@@ -28,4 +28,4 @@ log = "0.4.14"
|
||||
# Serialization
|
||||
serde = "1.0.125"
|
||||
serde_derive = "1.0.125"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
@@ -28,4 +28,4 @@ log = "0.4.14"
|
||||
# Serialization
|
||||
serde = "1.0.125"
|
||||
serde_derive = "1.0.125"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
@@ -36,14 +36,10 @@ clap = "2.34.0" # TODO: This is really out of date, but has conflicts when updat
|
||||
# NB: We switched to Tokio from `async-std` for broader ecosystem support.
|
||||
tokio = { version = "1.6.0", features = ["macros"] }
|
||||
|
||||
# MySql Database
|
||||
# "offline" supports typesafe builds without a live database
|
||||
# "rustls" doesn't appear to work with IP addresses, per:
|
||||
# https://github.com/launchbadge/sqlx/issues/1095#issuecomment-798050828
|
||||
sqlx = { version = "0.7.2", features = [ "mysql", "runtime-tokio", "tls-rustls", "chrono" ] }
|
||||
|
||||
elasticsearch = "8.5.0-alpha.1"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
[dev-dependencies]
|
||||
# None yet
|
||||
|
||||
@@ -33,12 +33,8 @@ log = "0.4.14"
|
||||
# NB: We switched to Tokio from `async-std` for broader ecosystem support.
|
||||
tokio = { version = "1.6.0", features = ["macros"] }
|
||||
|
||||
# MySql Database
|
||||
# "offline" supports typesafe builds without a live database
|
||||
# "rustls" doesn't appear to work with IP addresses, per:
|
||||
# https://github.com/launchbadge/sqlx/issues/1095#issuecomment-798050828
|
||||
sqlx = { version = "0.7.2", features = [ "mysql", "runtime-tokio", "tls-rustls", "chrono" ] }
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
[dev-dependencies]
|
||||
# None yet
|
||||
|
||||
@@ -33,10 +33,6 @@ strum = { version = "0.25", features = ["derive"] }
|
||||
# NB: We switched to Tokio from `async-std` for broader ecosystem support.
|
||||
tokio = { version = "1.6.0", features = ["macros"] }
|
||||
|
||||
# MySql Database
|
||||
# "offline" supports typesafe builds without a live database
|
||||
# "rustls" doesn't appear to work with IP addresses, per:
|
||||
# https://github.com/launchbadge/sqlx/issues/1095#issuecomment-798050828
|
||||
sqlx = { version = "0.7.2", features = [ "mysql", "runtime-tokio", "tls-rustls", "chrono" ] }
|
||||
|
||||
elasticsearch = "8.5.0-alpha.1"
|
||||
@@ -45,7 +41,7 @@ elasticsearch = "8.5.0-alpha.1"
|
||||
serde = "1.0.125"
|
||||
serde_derive = "1.0.125"
|
||||
serde_json = "1.0.108"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
[dev-dependencies]
|
||||
# None yet
|
||||
|
||||
@@ -23,7 +23,7 @@ log = "0.4.20"
|
||||
once_cell = "1.18.0"
|
||||
rand = "0.8.5"
|
||||
regex = "1.10.0"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
# Async Runtime
|
||||
# NB: Not using Tokio here since everything is blocking so far.
|
||||
|
||||
@@ -20,7 +20,7 @@ logging = { path = "../../lib/logging" }
|
||||
# External
|
||||
clap = { version = "4.4.7", features = ["derive"] }
|
||||
walkdir = "2.4.0"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
[dev-dependencies]
|
||||
# None yet
|
||||
|
||||
@@ -21,4 +21,4 @@ web_scrapers = { path = "../../lib/web_scrapers" }
|
||||
# External
|
||||
clap = "2.34.0" # TODO: This is really out of date, but has conflicts when updated
|
||||
tokio = { version = "1.6.0", features = ["macros"] }
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
@@ -34,7 +34,7 @@ futures-util = "0.3.29"
|
||||
# Serialization
|
||||
serde = "1.0.125"
|
||||
serde_json = "1.0.108"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
[dev-dependencies]
|
||||
# None yet
|
||||
|
||||
@@ -28,4 +28,4 @@ rust-s3 = { version = "0.33.0" }
|
||||
# Runtime
|
||||
# NB: We switched to Tokio from `async-std` for broader ecosystem support.
|
||||
tokio = { version = "1.6.0", features = ["macros"] }
|
||||
my-workspace-hack = { version = "0.1", path = "../../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
|
||||
@@ -20,7 +20,7 @@ tokens = { path = "../../../_types/tokens" }
|
||||
|
||||
# External
|
||||
bytes = "1.3"
|
||||
chrono = { version = "=0.4.22", features = ["serde"] }
|
||||
chrono = { version = "0.4.22", features = ["serde"] }
|
||||
log = "0.4.14"
|
||||
once_cell = "1.9.0"
|
||||
|
||||
|
||||
@@ -22,5 +22,5 @@ subprocess_common = { path = "../../subprocess_common" }
|
||||
anyhow = "1.0.75"
|
||||
log = "0.4.14"
|
||||
tempdir = "0.3.7"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
|
||||
|
||||
@@ -31,4 +31,4 @@ twitch_oauth2 = "0.6.0-rc.2"
|
||||
# Serialization
|
||||
serde = "1.0.125"
|
||||
serde_derive = "1.0.125"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
|
||||
@@ -23,7 +23,7 @@ server_environment = { path = "../server_environment" }
|
||||
dotenv = "0.15.0"
|
||||
hostname = "0.3.1"
|
||||
log = "0.4.14"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
[dev-dependencies]
|
||||
# None yet
|
||||
|
||||
@@ -22,4 +22,4 @@ anyhow = "1.0.75"
|
||||
|
||||
# In-memory caching
|
||||
lru_time_cache = "0.11.11"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
|
||||
@@ -23,7 +23,7 @@ r2d2_redis = "0.14.0"
|
||||
serde = "1.0.125"
|
||||
serde_derive = "1.0.125"
|
||||
serde_json = "1.0.108"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
|
||||
[dev-dependencies]
|
||||
# None yet
|
||||
|
||||
@@ -16,7 +16,7 @@ path = "src/lib.rs"
|
||||
[dependencies]
|
||||
# Internal
|
||||
errors = { path = "../errors" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
# External
|
||||
# KEEP THIS TO A MINIMUM OR NIL.
|
||||
|
||||
@@ -14,7 +14,7 @@ path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
# Internal
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
# External
|
||||
# (None yet)
|
||||
|
||||
@@ -21,7 +21,7 @@ errors = { path = "../errors" }
|
||||
hmac = "0.10.0" # jwt signing
|
||||
jwt = "0.13.0"
|
||||
sha2 = "0.9.5" # hmac signing
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
[dev-dependencies]
|
||||
# None yet
|
||||
|
||||
@@ -16,7 +16,7 @@ path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
rand = "0.8.5"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
[dev-dependencies]
|
||||
# None yet
|
||||
|
||||
@@ -13,9 +13,9 @@ name = "datetimes"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
chrono = { version = "=0.4.22", features = ["serde"] }
|
||||
chrono = { version = "0.4.22", features = ["serde"] }
|
||||
once_cell = "1.18.0"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
[dev-dependencies]
|
||||
# (none)
|
||||
@@ -21,4 +21,4 @@ easyenv = { path = "../../../lib/easyenv" }
|
||||
# External
|
||||
anyhow = "1.0.75"
|
||||
url = "2.4.1"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
|
||||
@@ -24,7 +24,7 @@ log = "0.4.14"
|
||||
# Serialization
|
||||
serde = { version = "1.0.125", features = ["derive"] }
|
||||
toml = "0.5.8"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ reusable_types = { path = "../../../_types/reusable_types" }
|
||||
# External
|
||||
anyhow = "1.0.75"
|
||||
base64 = "0.21.0"
|
||||
chrono = { version = "=0.4.22", features = ["serde"] }
|
||||
chrono = { version = "0.4.22", features = ["serde"] }
|
||||
log = "0.4.14"
|
||||
once_cell = "1.18.0"
|
||||
regex = "1.5.4"
|
||||
@@ -39,7 +39,7 @@ language-tags = "0.3.2" # Parsing single tags richly
|
||||
serde = "1.0.125"
|
||||
serde_derive = "1.0.125"
|
||||
serde_json = "1.0.108"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
|
||||
[dev-dependencies]
|
||||
actix-rt = "2.9.0"
|
||||
|
||||
@@ -20,7 +20,7 @@ storyteller_root = { path = "../storyteller_root" }
|
||||
dotenv = "0.15.0"
|
||||
env_logger = "0.10.1"
|
||||
log = "0.4.14"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
[dev-dependencies]
|
||||
# None yet
|
||||
|
||||
@@ -23,10 +23,10 @@ elasticsearch = "8.5.0-alpha.1"
|
||||
log = "0.4.14"
|
||||
|
||||
# Serialization
|
||||
chrono = { version = "=0.4.22", features = ["serde"] }
|
||||
chrono = { version = "0.4.22", features = ["serde"] }
|
||||
serde = { version = "1.0.152", features = ["derive"] }
|
||||
serde_json = "1.0.108"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
[dev-dependencies]
|
||||
# None yet
|
||||
|
||||
@@ -27,7 +27,7 @@ pub async fn search_tts_models(
|
||||
|
||||
let mut response_json = search_response.json::<Value>().await?;
|
||||
|
||||
let mut hits = response_json.get_mut("hits")
|
||||
let hits = response_json.get_mut("hits")
|
||||
.map(|hits| hits.take());
|
||||
|
||||
let hits = hits.map(|mut hits| {
|
||||
|
||||
@@ -11,5 +11,5 @@ path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
errors = { path = "../errors" }
|
||||
lettre = "0.11.0"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
lettre = "0.11.2"
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
@@ -18,7 +18,7 @@ path = "src/lib.rs"
|
||||
# Consider the dependencies here wisely.
|
||||
# Ideally we have almost nothing as a dependency of this crate.
|
||||
anyhow = "1.0.75"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
[dev-dependencies]
|
||||
# None yet
|
||||
|
||||
@@ -20,7 +20,7 @@ errors = { path = "../../errors" }
|
||||
|
||||
# External
|
||||
zip = "0.6.6"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
|
||||
[dev-dependencies]
|
||||
# None yet
|
||||
|
||||
@@ -16,7 +16,7 @@ path = "src/lib.rs"
|
||||
[dependencies]
|
||||
# Internal
|
||||
errors = { path = "../../errors" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
log = "0.4.20"
|
||||
|
||||
# External
|
||||
|
||||
@@ -22,7 +22,7 @@ bcrypt = "0.8" # password hashes
|
||||
data-encoding = "2.3.2"
|
||||
md-5 = "0.9.1" # DO NOT USE FOR SERIOUS CRYPTO (we use this for gravatar)
|
||||
ring = "0.17.0-alpha.10"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
|
||||
[dev-dependencies]
|
||||
# None yet
|
||||
|
||||
@@ -21,7 +21,7 @@ errors = { path = "../../errors" }
|
||||
|
||||
# External
|
||||
image = "0.24.1"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
|
||||
[dev-dependencies]
|
||||
testing = { path = "../../testing" }
|
||||
|
||||
@@ -26,7 +26,7 @@ log = "0.4.14"
|
||||
# Opus is the browser's default (only) recording codec: https://blog.addpipe.com/audio-constraints-getusermedia/
|
||||
symphonia = { git = "https://github.com/pdeljanov/Symphonia.git", rev = "e1a70095c4409478c1ded499fb8dd4afa540fb90", features = ["aac", "alac", "flac", "isomp4", "mkv", "mp3", "ogg", "opus", "vorbis", "wav"] }
|
||||
|
||||
my-workspace-hack = { version = "0.1", path = "../../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
|
||||
[dev-dependencies]
|
||||
# None yet
|
||||
|
||||
@@ -16,7 +16,7 @@ path = "src/lib.rs"
|
||||
[dependencies]
|
||||
# External
|
||||
infer = "0.11" # Mimetype detection
|
||||
my-workspace-hack = { version = "0.1", path = "../../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
|
||||
[dev-dependencies]
|
||||
# None yet
|
||||
|
||||
@@ -19,7 +19,7 @@ path = "src/lib.rs"
|
||||
|
||||
# External
|
||||
uuid = { version = "0.8.2", features = ["v4"] }
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
[dev-dependencies]
|
||||
# None yet
|
||||
|
||||
@@ -24,7 +24,7 @@ redis_common = { path = "../redis_common" }
|
||||
|
||||
# External
|
||||
anyhow = "1.0.75"
|
||||
chrono = { version = "=0.4.22", features = ["serde"] }
|
||||
chrono = { version = "0.4.22", features = ["serde"] }
|
||||
log = "0.4.14"
|
||||
r2d2_redis = "0.14.0"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
@@ -17,7 +17,7 @@ path = "src/lib.rs"
|
||||
dotenv = "0.15.0"
|
||||
env_logger = "0.10.1"
|
||||
log = "0.4.20"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
[dev-dependencies]
|
||||
# None yet
|
||||
|
||||
@@ -25,7 +25,7 @@ tokens = { path = "../../_types/tokens" }
|
||||
|
||||
# External
|
||||
anyhow = "1.0.75"
|
||||
chrono = { version = "=0.4.22", features = ["serde"] }
|
||||
chrono = { version = "0.4.22", features = ["serde"] }
|
||||
dotenv = "0.15.0"
|
||||
log = "0.4.14"
|
||||
|
||||
@@ -39,14 +39,10 @@ serde_derive = "1.0.125"
|
||||
serde_json = "1.0.108"
|
||||
toml = "0.5.8"
|
||||
serial_test = "2.0.0"
|
||||
# MySql Database
|
||||
# "offline" supports typesafe builds without a live database
|
||||
# "rustls" doesn't appear to work with IP addresses, per:
|
||||
# https://github.com/launchbadge/sqlx/issues/1095#issuecomment-798050828
|
||||
|
||||
tokio = { version = "1.6.0", features = ["full"] }
|
||||
rand = "0.8"
|
||||
sqlx = { version = "0.7.2", features = [ "mysql", "runtime-tokio", "tls-rustls", "chrono" ] }
|
||||
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
|
||||
+1
-1
@@ -167,7 +167,7 @@ FROM email_sender_jobs"#.to_string();
|
||||
LIMIT ?
|
||||
"#);
|
||||
|
||||
let mut query = sqlx::query_as::<_, AvailableEmailSenderJobRawInternal>(&query)
|
||||
let query = sqlx::query_as::<_, AvailableEmailSenderJobRawInternal>(&query)
|
||||
.bind(args.is_debug_worker)
|
||||
.bind(args.num_records);
|
||||
|
||||
|
||||
+1
-1
@@ -336,7 +336,7 @@ FROM generic_inference_jobs"#.to_string();
|
||||
LIMIT ?
|
||||
"#);
|
||||
|
||||
let mut query = sqlx::query_as::<_, AvailableInferenceJobRawInternal>(&query)
|
||||
let query = sqlx::query_as::<_, AvailableInferenceJobRawInternal>(&query)
|
||||
.bind(args.is_debug_worker)
|
||||
.bind(args.num_records);
|
||||
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ pub async fn mark_generic_inference_job_failure(
|
||||
// statuses: "attempt_failed", "complete_failure", "dead"
|
||||
let mut next_status = "attempt_failed";
|
||||
|
||||
let mut maybe_public_failure_reason = maybe_public_failure_reason.map(|reason| {
|
||||
let maybe_public_failure_reason = maybe_public_failure_reason.map(|reason| {
|
||||
let mut reason = reason.trim().to_string();
|
||||
reason.truncate(512); // Max length of column is 512
|
||||
reason
|
||||
|
||||
+69
-6
@@ -14,7 +14,7 @@ use tokens::tokens::users::UserToken;
|
||||
|
||||
use crate::helpers::boolean_converters::i8_to_bool;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct GenericInferenceJobStatus {
|
||||
pub job_token: InferenceJobToken,
|
||||
|
||||
@@ -40,7 +40,7 @@ pub struct GenericInferenceJobStatus {
|
||||
|
||||
/// Details about the user's original inference request
|
||||
/// (We may want to present it in the "pending" UI.)
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct RequestDetails {
|
||||
pub inference_category: InferenceCategory,
|
||||
pub maybe_model_type: Option<String>, // TODO: Strongly type
|
||||
@@ -52,7 +52,7 @@ pub struct RequestDetails {
|
||||
}
|
||||
|
||||
/// Details about the generated result
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct ResultDetails {
|
||||
pub entity_type: String,
|
||||
pub entity_token: String,
|
||||
@@ -71,7 +71,7 @@ pub struct ResultDetails {
|
||||
|
||||
/// NB: DO NOT EXPOSE TO FRONTEND.
|
||||
/// This is used to gate access to job termination
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct UserDetails {
|
||||
pub maybe_creator_user_token: Option<UserToken>,
|
||||
pub maybe_creator_anonymous_visitor_token: Option<AnonymousVisitorTrackingToken>,
|
||||
@@ -168,6 +168,11 @@ WHERE jobs.token = ?
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Some(raw_record_to_public_result(record)))
|
||||
}
|
||||
|
||||
/// Map the internal record type (since we query over several result tables)
|
||||
fn raw_record_to_public_result(record: RawGenericInferenceJobStatus) -> GenericInferenceJobStatus {
|
||||
let maybe_model_title = match record.inference_category {
|
||||
InferenceCategory::LipsyncAnimation => Some("lipsync animation"),
|
||||
InferenceCategory::TextToSpeech => record.maybe_tts_model_title.as_deref(),
|
||||
@@ -213,7 +218,7 @@ WHERE jobs.token = ?
|
||||
})
|
||||
});
|
||||
|
||||
Ok(Some(GenericInferenceJobStatus {
|
||||
GenericInferenceJobStatus {
|
||||
job_token: record.job_token,
|
||||
status: record.status,
|
||||
attempt_count: record.attempt_count,
|
||||
@@ -237,9 +242,10 @@ WHERE jobs.token = ?
|
||||
is_keepalive_required: i8_to_bool(record.is_keepalive_required),
|
||||
created_at: record.created_at,
|
||||
updated_at: record.updated_at,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct RawGenericInferenceJobStatus {
|
||||
pub job_token: InferenceJobToken,
|
||||
|
||||
@@ -281,3 +287,60 @@ struct RawGenericInferenceJobStatus {
|
||||
pub maybe_successfully_completed_at: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use enums::by_table::generic_inference_jobs::inference_category::InferenceCategory;
|
||||
use crate::queries::generic_inference::web::get_inference_job_status::{raw_record_to_public_result, RawGenericInferenceJobStatus};
|
||||
|
||||
#[test]
|
||||
fn text_to_speech_as_media_file() {
|
||||
// NB(bt,2023-12-06): After tts migration to media files, these are the results the job system will return
|
||||
let record = RawGenericInferenceJobStatus {
|
||||
inference_category: InferenceCategory::TextToSpeech,
|
||||
maybe_result_entity_type: Some("media_file".to_string()), // NB: Media file record
|
||||
maybe_result_entity_token: Some("m_00af018cy75pxytpb8wbdx9jqgtp0p".to_string()),
|
||||
maybe_media_file_public_bucket_directory_hash: Some("3vb91yq71z5zne56saazn4qntt52yter".to_string()), // NB: Media file
|
||||
maybe_media_file_public_bucket_prefix: Some("fakeyou_".to_string()),
|
||||
maybe_media_file_public_bucket_extension: Some(".wav".to_string()),
|
||||
maybe_tts_public_bucket_path: None, // NB: Not a tts_result!
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let record = raw_record_to_public_result(record);
|
||||
|
||||
assert!(record.maybe_result_details.is_some());
|
||||
|
||||
let result_details = record.maybe_result_details.expect("should have result details");
|
||||
|
||||
assert_eq!(&result_details.entity_type, "media_file");
|
||||
assert_eq!(&result_details.entity_token, "m_00af018cy75pxytpb8wbdx9jqgtp0p");
|
||||
assert_eq!(&result_details.public_bucket_location_or_hash, "3vb91yq71z5zne56saazn4qntt52yter");
|
||||
assert_eq!(result_details.public_bucket_location_is_hash, true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn text_to_speech_as_tts_result() {
|
||||
// NB(bt,2023-12-06): Prior to tts migration to media files, these are the results the job system will return
|
||||
let record = RawGenericInferenceJobStatus {
|
||||
inference_category: InferenceCategory::TextToSpeech,
|
||||
maybe_result_entity_type: Some("text_to_speech".to_string()), // NB: TTS record
|
||||
maybe_result_entity_token: Some("TR:wefhbk4j3yc8d6zwembedbdw4ad4s".to_string()),
|
||||
maybe_tts_public_bucket_path: Some("/tts_inference_output/c/5/8/vocodes_c58aeaef-84df-4478-9e7f-c64280a852e8.wav".to_string()), // NB: tts_result!
|
||||
maybe_media_file_public_bucket_directory_hash: None, // NB: Not a media file!
|
||||
maybe_media_file_public_bucket_prefix: None,
|
||||
maybe_media_file_public_bucket_extension: None,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let record = raw_record_to_public_result(record);
|
||||
|
||||
assert!(record.maybe_result_details.is_some());
|
||||
|
||||
let result_details = record.maybe_result_details.expect("should have result details");
|
||||
|
||||
assert_eq!(&result_details.entity_type, "text_to_speech");
|
||||
assert_eq!(&result_details.entity_token, "TR:wefhbk4j3yc8d6zwembedbdw4ad4s");
|
||||
assert_eq!(&result_details.public_bucket_location_or_hash, "/tts_inference_output/c/5/8/vocodes_c58aeaef-84df-4478-9e7f-c64280a852e8.wav");
|
||||
assert_eq!(result_details.public_bucket_location_is_hash, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
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::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;
|
||||
|
||||
pub struct InsertMediaFileArgs<'a> {
|
||||
pub pool: &'a MySqlPool,
|
||||
pub job: &'a AvailableInferenceJob,
|
||||
|
||||
pub maybe_mime_type: Option<&'a str>,
|
||||
pub file_size_bytes: u64,
|
||||
pub duration_millis: u64,
|
||||
pub sha256_checksum: &'a str,
|
||||
|
||||
// TODO: Media duration.
|
||||
//pub duration_millis: u64,
|
||||
|
||||
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 async fn insert_media_file_from_tacotron2(
|
||||
args: InsertMediaFileArgs<'_>
|
||||
) -> AnyhowResult<(MediaFileToken, u64)>
|
||||
{
|
||||
let result_token = MediaFileToken::generate();
|
||||
|
||||
let origin_model_type = MediaFileOriginModelType::Tacotron2;
|
||||
|
||||
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?;
|
||||
|
||||
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_voice_conversion_id = transactional_increment_generic_synthetic_id(
|
||||
&user_token,
|
||||
IdCategory::TtsResult,
|
||||
&mut transaction
|
||||
).await?;
|
||||
|
||||
maybe_creator_file_synthetic_id = Some(next_media_file_id);
|
||||
maybe_creator_category_synthetic_id = Some(next_voice_conversion_id);
|
||||
}
|
||||
|
||||
let vc_model_token = args.job.maybe_model_token.as_deref();
|
||||
let creator_ip_address = args.job.creator_ip_address.as_str();
|
||||
let creator_set_visibility = args.job.creator_set_visibility.clone();
|
||||
|
||||
const ORIGIN_CATEGORY : MediaFileOriginCategory = MediaFileOriginCategory::Inference;
|
||||
const ORIGIN_PRODUCT_CATEGORY : MediaFileOriginProductCategory = MediaFileOriginProductCategory::TextToSpeech;
|
||||
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 = ?,
|
||||
maybe_origin_model_token = ?,
|
||||
|
||||
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(),
|
||||
args.job.maybe_model_token,
|
||||
|
||||
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))
|
||||
}
|
||||
@@ -0,0 +1,262 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use sqlx::{FromRow, MySql, MySqlPool, QueryBuilder, Row};
|
||||
use sqlx::mysql::MySqlRow;
|
||||
|
||||
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 enums::common::visibility::Visibility;
|
||||
use enums::traits::mysql_from_row::MySqlFromRow;
|
||||
use errors::AnyhowResult;
|
||||
use tokens::tokens::media_files::MediaFileToken;
|
||||
use tokens::tokens::users::UserToken;
|
||||
|
||||
pub struct MediaFileListPage {
|
||||
pub records: Vec<MediaFileListItem>,
|
||||
|
||||
pub sort_ascending: bool,
|
||||
|
||||
/// ID of the first record.
|
||||
pub first_id: Option<i64>,
|
||||
|
||||
/// ID of the last record.
|
||||
pub last_id: Option<i64>,
|
||||
}
|
||||
|
||||
pub struct MediaFileListItem {
|
||||
pub token: MediaFileToken,
|
||||
|
||||
pub origin_category: MediaFileOriginCategory,
|
||||
pub origin_product_category: MediaFileOriginProductCategory,
|
||||
pub maybe_origin_model_type: Option<MediaFileOriginModelType>,
|
||||
pub maybe_origin_model_token: Option<String>,
|
||||
|
||||
pub media_type: MediaFileType,
|
||||
pub public_bucket_directory_hash: String,
|
||||
pub maybe_public_bucket_prefix: Option<String>,
|
||||
pub maybe_public_bucket_extension: Option<String>,
|
||||
|
||||
pub maybe_creator_user_token: Option<UserToken>,
|
||||
pub maybe_creator_username: Option<String>,
|
||||
pub maybe_creator_display_name: Option<String>,
|
||||
pub maybe_creator_gravatar_hash: Option<String>,
|
||||
|
||||
pub creator_set_visibility: Visibility,
|
||||
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub updated_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum ViewAs {
|
||||
Moderator,
|
||||
NonModerator,
|
||||
}
|
||||
|
||||
pub struct ListMediaFilesArgs<'a> {
|
||||
pub limit: usize,
|
||||
pub maybe_filter_media_type: Option<MediaFileType>,
|
||||
pub maybe_offset: Option<usize>,
|
||||
pub cursor_is_reversed: bool,
|
||||
pub view_as: ViewAs,
|
||||
pub mysql_pool: &'a MySqlPool,
|
||||
}
|
||||
|
||||
pub async fn list_media_files(args: ListMediaFilesArgs<'_>) -> AnyhowResult<MediaFileListPage> {
|
||||
|
||||
let mut query = query_builder(
|
||||
args.maybe_filter_media_type,
|
||||
args.limit,
|
||||
args.maybe_offset,
|
||||
args.cursor_is_reversed,
|
||||
args.view_as,
|
||||
);
|
||||
|
||||
let query = query.build_query_as::<MediaFileListItemInternal>();
|
||||
|
||||
let results = query.fetch_all(args.mysql_pool).await?;
|
||||
|
||||
let first_id = results.first()
|
||||
.map(|raw_result| raw_result.id);
|
||||
|
||||
let last_id = results.last()
|
||||
.map(|raw_result| raw_result.id);
|
||||
|
||||
let results = results.into_iter()
|
||||
.map(|record| {
|
||||
MediaFileListItem {
|
||||
token: record.token,
|
||||
origin_category: record.origin_category,
|
||||
origin_product_category: record.origin_product_category,
|
||||
maybe_origin_model_type: record.maybe_origin_model_type,
|
||||
maybe_origin_model_token: record.maybe_origin_model_token,
|
||||
media_type: record.media_type,
|
||||
public_bucket_directory_hash: record.public_bucket_directory_hash,
|
||||
maybe_public_bucket_prefix: record.maybe_public_bucket_prefix,
|
||||
maybe_public_bucket_extension: record.maybe_public_bucket_extension,
|
||||
maybe_creator_user_token: record.maybe_creator_user_token,
|
||||
maybe_creator_username: record.maybe_creator_username,
|
||||
maybe_creator_display_name: record.maybe_creator_display_name,
|
||||
maybe_creator_gravatar_hash: record.maybe_creator_gravatar_hash,
|
||||
creator_set_visibility: record.creator_set_visibility,
|
||||
created_at: record.created_at,
|
||||
updated_at: record.updated_at,
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
Ok(MediaFileListPage {
|
||||
records: results,
|
||||
sort_ascending: !args.cursor_is_reversed,
|
||||
first_id,
|
||||
last_id,
|
||||
})
|
||||
}
|
||||
|
||||
fn query_builder<'a>(
|
||||
maybe_filter_media_type: Option<MediaFileType>,
|
||||
limit: usize,
|
||||
maybe_offset: Option<usize>,
|
||||
cursor_is_reversed: bool,
|
||||
view_as: ViewAs,
|
||||
) -> QueryBuilder<'a, MySql> {
|
||||
|
||||
// NB: Query cannot be statically checked by sqlx
|
||||
let mut query_builder: QueryBuilder<MySql> = QueryBuilder::new(
|
||||
r#"
|
||||
SELECT
|
||||
m.id,
|
||||
m.token,
|
||||
|
||||
m.origin_category,
|
||||
m.origin_product_category,
|
||||
|
||||
m.maybe_origin_model_type,
|
||||
m.maybe_origin_model_token,
|
||||
|
||||
m.media_type,
|
||||
|
||||
m.public_bucket_directory_hash,
|
||||
m.maybe_public_bucket_prefix,
|
||||
m.maybe_public_bucket_extension,
|
||||
|
||||
m.maybe_creator_user_token,
|
||||
u.username as maybe_creator_username,
|
||||
u.display_name as maybe_creator_display_name,
|
||||
u.email_gravatar_hash as maybe_creator_gravatar_hash,
|
||||
|
||||
m.creator_set_visibility,
|
||||
m.created_at,
|
||||
m.updated_at
|
||||
|
||||
FROM media_files AS m
|
||||
LEFT OUTER JOIN users AS u
|
||||
ON m.maybe_creator_user_token = u.token
|
||||
|
||||
WHERE m.user_deleted_at IS NULL
|
||||
AND m.mod_deleted_at IS NULL
|
||||
"#
|
||||
);
|
||||
|
||||
if let Some(media_type) = maybe_filter_media_type {
|
||||
// FIXME: Binding shouldn't require to_str().
|
||||
// Otherwise, it's calling the Display trait on the raw type which is resulting in an
|
||||
// incorrect binding and runtime error.
|
||||
query_builder.push(" AND m.media_file_type = ");
|
||||
query_builder.push_bind(media_type.to_str());
|
||||
}
|
||||
|
||||
match view_as {
|
||||
ViewAs::Moderator => {}
|
||||
ViewAs::NonModerator=> {
|
||||
// FIXME: Binding shouldn't require to_str().
|
||||
// Otherwise, it's calling the Display trait on the raw type which is resulting in an
|
||||
// incorrect binding and runtime error.
|
||||
query_builder.push(" AND m.creator_set_visibility = ");
|
||||
query_builder.push_bind(Visibility::Public.to_str());
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(offset) = maybe_offset {
|
||||
if cursor_is_reversed {
|
||||
query_builder.push(format!(" AND m.id < {offset} "));
|
||||
} else {
|
||||
query_builder.push(format!(" AND m.id > {offset} "));
|
||||
}
|
||||
}
|
||||
|
||||
if cursor_is_reversed {
|
||||
query_builder.push(" ORDER BY m.id ASC ");
|
||||
} else {
|
||||
query_builder.push(" ORDER BY m.id DESC ");
|
||||
}
|
||||
|
||||
query_builder.push(format!(" LIMIT {limit} "));
|
||||
|
||||
query_builder
|
||||
}
|
||||
|
||||
struct MediaFileListItemInternal {
|
||||
id: i64,
|
||||
token: MediaFileToken,
|
||||
|
||||
origin_category: MediaFileOriginCategory,
|
||||
origin_product_category: MediaFileOriginProductCategory,
|
||||
maybe_origin_model_type: Option<MediaFileOriginModelType>,
|
||||
maybe_origin_model_token: Option<String>,
|
||||
|
||||
media_type: MediaFileType,
|
||||
public_bucket_directory_hash: String,
|
||||
maybe_public_bucket_prefix: Option<String>,
|
||||
maybe_public_bucket_extension: Option<String>,
|
||||
|
||||
maybe_creator_user_token: Option<UserToken>,
|
||||
maybe_creator_username: Option<String>,
|
||||
maybe_creator_display_name: Option<String>,
|
||||
maybe_creator_gravatar_hash: Option<String>,
|
||||
|
||||
creator_set_visibility: Visibility,
|
||||
|
||||
created_at: DateTime<Utc>,
|
||||
updated_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
// NB(bt,2023-12-05): There's an issue with type hinting in the `as` clauses with QueryBuilder (or
|
||||
// raw query strings) and sqlx::FromRow, regardless of whether it is derived of manually
|
||||
// implemented. Perhaps this will improve in the future, but for now manually constructed queries
|
||||
// cannot have type hints, eg. the following:
|
||||
//
|
||||
// m.token as `token: tokens::tokens::media_files::MediaFileToken`,
|
||||
// m.origin_category as `origin_category: enums::by_table::media_files::media_file_origin_category::MediaFileOriginCategory`,
|
||||
// m.creator_set_visibility as `creator_set_visibility: enums::common::visibility::Visibility`,
|
||||
//
|
||||
// This results in the automatic mapping not being able to be found by name (for macro derive), and
|
||||
// in the manual case `row.try_get()` etc. won't have the correct column name (since the name is the
|
||||
// full "as" clause).
|
||||
impl FromRow<'_, MySqlRow> for MediaFileListItemInternal {
|
||||
fn from_row(row: &MySqlRow) -> Result<Self, sqlx::Error> {
|
||||
let maybe_creator_user_token : Option<String> = row.try_get("maybe_creator_user_token")?;
|
||||
let maybe_creator_user_token = maybe_creator_user_token.map(|user_token| UserToken::new(user_token));
|
||||
|
||||
Ok(Self {
|
||||
id: row.try_get("id")?,
|
||||
token: MediaFileToken::new(row.try_get("token")?),
|
||||
origin_category: MediaFileOriginCategory::try_from_mysql_row(row, "origin_category")?,
|
||||
origin_product_category: MediaFileOriginProductCategory::try_from_mysql_row(row, "origin_product_category")?,
|
||||
maybe_origin_model_type: MediaFileOriginModelType::try_from_mysql_row_nullable(row, "maybe_origin_model_type")?,
|
||||
maybe_origin_model_token: row.try_get("maybe_origin_model_token")?,
|
||||
media_type: MediaFileType::try_from_mysql_row(row, "media_type")?,
|
||||
public_bucket_directory_hash: row.try_get("public_bucket_directory_hash")?,
|
||||
maybe_public_bucket_prefix: row.try_get("maybe_public_bucket_prefix")?,
|
||||
maybe_public_bucket_extension: row.try_get("maybe_public_bucket_extension")?,
|
||||
maybe_creator_user_token,
|
||||
maybe_creator_username: row.try_get("maybe_creator_username")?,
|
||||
maybe_creator_display_name: row.try_get("maybe_creator_display_name")?,
|
||||
maybe_creator_gravatar_hash: row.try_get("maybe_creator_gravatar_hash")?,
|
||||
creator_set_visibility: Visibility::try_from_mysql_row(row, "creator_set_visibility")?,
|
||||
created_at: row.try_get("created_at")?,
|
||||
updated_at: row.try_get("updated_at")?,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -156,6 +156,7 @@ WHERE m.user_deleted_at IS NULL
|
||||
// Otherwise, it's calling the Display trait on the raw type which is resulting in an
|
||||
// incorrect binding and runtime error.
|
||||
query_builder.push(" AND m.media_file_type = ");
|
||||
query_builder.push_bind(media_type.to_str());
|
||||
}
|
||||
|
||||
match view_as {
|
||||
|
||||
@@ -2,7 +2,9 @@ pub mod delete_media_file;
|
||||
pub mod get_media_file;
|
||||
pub mod insert_media_file_from_cli_tool;
|
||||
pub mod insert_media_file_from_face_animation;
|
||||
pub mod insert_media_file_from_tacotron2;
|
||||
pub mod insert_media_file_from_voice_conversion;
|
||||
pub mod insert_media_file_from_zero_shot_tts;
|
||||
pub mod list_media_files;
|
||||
pub mod list_media_files_for_user;
|
||||
pub mod update_media_file;
|
||||
|
||||
@@ -14,7 +14,7 @@ pub struct UpdateMediaFileArgs<'a> {
|
||||
|
||||
pub async fn update_media_file(args: UpdateMediaFileArgs<'_>) -> AnyhowResult<()>{
|
||||
// TODO: enforce checks for idempotency token
|
||||
let mut transaction = args.mysql_pool.begin().await?;
|
||||
let transaction = args.mysql_pool.begin().await?;
|
||||
let query_result = sqlx::query!(
|
||||
r#"
|
||||
UPDATE media_files
|
||||
|
||||
+3
-3
@@ -184,7 +184,7 @@ impl ListCategoriesQueryBuilder {
|
||||
query = query.bind(model_type);
|
||||
}
|
||||
|
||||
let mut results = query.fetch_all(&mut **mysql_connection)
|
||||
let results = query.fetch_all(&mut **mysql_connection)
|
||||
.await?;
|
||||
|
||||
Ok(results)
|
||||
@@ -239,7 +239,7 @@ LEFT OUTER JOIN users
|
||||
|
||||
let mut query = "".to_string();
|
||||
|
||||
if let Some(username) = self.scope_creator_user_token.as_deref() {
|
||||
if let Some(_username) = self.scope_creator_user_token.as_deref() {
|
||||
if !first_predicate_added {
|
||||
query.push_str(" WHERE model_categories.creator_user_token = ?");
|
||||
first_predicate_added = true;
|
||||
@@ -248,7 +248,7 @@ LEFT OUTER JOIN users
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(model_type) = self.scope_model_type.as_deref() {
|
||||
if let Some(_model_type) = self.scope_model_type.as_deref() {
|
||||
if !first_predicate_added {
|
||||
query.push_str(" WHERE model_categories.model_type = ?");
|
||||
first_predicate_added = true;
|
||||
|
||||
@@ -16,7 +16,7 @@ pub struct UpdateWeightArgs<'a> {
|
||||
}
|
||||
|
||||
pub async fn update_weights(args: UpdateWeightArgs<'_>) -> AnyhowResult<()> {
|
||||
let mut transaction = args.mysql_pool.begin().await?;
|
||||
let transaction = args.mysql_pool.begin().await?;
|
||||
|
||||
let query_result = sqlx
|
||||
::query!(
|
||||
|
||||
+1
-1
@@ -63,7 +63,7 @@ pub async fn list_trending_tts_models(
|
||||
];
|
||||
|
||||
let query = query_parts.join(" UNION ");
|
||||
let mut query = sqlx::query_as::<_, RawTrendingModel>(&query);
|
||||
let query = sqlx::query_as::<_, RawTrendingModel>(&query);
|
||||
|
||||
let results = query.fetch_all(&mut **mysql_connection).await?;
|
||||
|
||||
|
||||
+1
-1
@@ -159,7 +159,7 @@ impl ListAssignedTtsCategoriesQueryBuilder {
|
||||
// NB: Model token is always used for scoping.
|
||||
query = query.bind(&self.scope_tts_model_token);
|
||||
|
||||
let mut results = query.fetch_all(&mut **mysql_connection)
|
||||
let results = query.fetch_all(&mut **mysql_connection)
|
||||
.await?;
|
||||
|
||||
Ok(results)
|
||||
|
||||
+1
-1
@@ -192,7 +192,7 @@ pub async fn mark_tts_upload_job_done(
|
||||
{
|
||||
let status = if success { "complete_success" } else { "complete_failure" };
|
||||
|
||||
let query_result = sqlx::query!(
|
||||
let _query_result = sqlx::query!(
|
||||
r#"
|
||||
UPDATE tts_model_upload_jobs
|
||||
SET
|
||||
|
||||
+1
-1
@@ -268,7 +268,7 @@ LEFT OUTER JOIN users
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(username) = self.scope_creator_username.as_deref() {
|
||||
if let Some(_username) = self.scope_creator_username.as_deref() {
|
||||
if !first_predicate_added {
|
||||
query.push_str(" WHERE users.username = ?");
|
||||
first_predicate_added = true;
|
||||
|
||||
+1
-1
@@ -93,7 +93,7 @@ SET
|
||||
"#, query_inner_positions, query_inner_ip_addresses, user_token, rule_tokens);
|
||||
|
||||
// NB: This, unfortunately, cannot be statically checked.
|
||||
let mut query = sqlx::query(&query);
|
||||
let query = sqlx::query(&query);
|
||||
|
||||
let result = query.execute(mysql_pool).await;
|
||||
|
||||
|
||||
@@ -145,7 +145,7 @@ impl TwitchOauthTokenFinder {
|
||||
query = query.bind(twitch_username);
|
||||
}
|
||||
|
||||
let mut result = query.fetch_optional(mysql_pool).await;
|
||||
let result = query.fetch_optional(mysql_pool).await;
|
||||
|
||||
match result {
|
||||
Ok(Some(record)) => {
|
||||
|
||||
@@ -65,10 +65,10 @@ impl ListUsersQueryBuilder {
|
||||
|
||||
let internal_results = self.internal_query(mysql_pool).await?;
|
||||
|
||||
let mut first_id = internal_results.first()
|
||||
let first_id = internal_results.first()
|
||||
.map(|raw_result| raw_result.user_id);
|
||||
|
||||
let mut last_id = internal_results.last()
|
||||
let last_id = internal_results.last()
|
||||
.map(|raw_result| raw_result.user_id);
|
||||
|
||||
let users = internal_results
|
||||
@@ -106,17 +106,17 @@ impl ListUsersQueryBuilder {
|
||||
) -> AnyhowResult<Vec<UserForListRaw>> {
|
||||
|
||||
let query = self.build_query_string();
|
||||
let mut query = sqlx::query_as::<_, UserForListRaw>(&query);
|
||||
let query = sqlx::query_as::<_, UserForListRaw>(&query);
|
||||
|
||||
|
||||
let mut results = query.fetch_all(mysql_pool)
|
||||
let results = query.fetch_all(mysql_pool)
|
||||
.await?;
|
||||
|
||||
Ok(results)
|
||||
}
|
||||
|
||||
pub fn build_query_string(&self) -> String {
|
||||
let mut query_string = r#"
|
||||
let query_string = r#"
|
||||
SELECT
|
||||
id as user_id,
|
||||
token as user_token,
|
||||
|
||||
@@ -19,7 +19,7 @@ errors = { path = "../errors" }
|
||||
|
||||
# External
|
||||
bcrypt = "0.8" # password hashes
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
#hmac = "0.10.0" # jwt signing
|
||||
#jwt = "0.13.0"
|
||||
#sha2 = "0.9.5" # hmac signing
|
||||
|
||||
@@ -27,4 +27,4 @@ serde_json = "1.0.108"
|
||||
|
||||
# TODO: Get rid of in favor of std::time
|
||||
time = "0.3.30"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
@@ -15,7 +15,7 @@ path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
# External
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
[dev-dependencies]
|
||||
# None yet
|
||||
|
||||
@@ -20,7 +20,7 @@ errors = { path = "../../lib/errors" }
|
||||
tokens = { path = "../../_types/tokens" }
|
||||
|
||||
# External
|
||||
chrono = { version = "=0.4.22", features = ["serde"] }
|
||||
chrono = { version = "0.4.22", features = ["serde"] }
|
||||
dotenv = "0.15.0"
|
||||
log = "0.4.14"
|
||||
|
||||
@@ -28,11 +28,6 @@ log = "0.4.14"
|
||||
once_cell = "1.9.0"
|
||||
regex = "1.5.4"
|
||||
|
||||
# SQlite Database
|
||||
# "offline" supports typesafe builds without a live database
|
||||
# "rustls" doesn't appear to work with IP addresses, per:
|
||||
# https://github.com/launchbadge/sqlx/issues/1095#issuecomment-798050828
|
||||
# ^^^ Granted, this applies to *MySQL* and probably not SQLite for our use case here ^^^
|
||||
sqlx = { version = "0.7.2", features = [ "sqlite", "runtime-tokio-native-tls", "chrono" ] }
|
||||
|
||||
[dev-dependencies]
|
||||
|
||||
@@ -16,12 +16,8 @@ path = "src/lib.rs"
|
||||
# Internal
|
||||
errors = { path = "../errors" }
|
||||
|
||||
# MySql Database
|
||||
# "offline" supports typesafe builds without a live database
|
||||
# "rustls" doesn't appear to work with IP addresses, per:
|
||||
# https://github.com/launchbadge/sqlx/issues/1095#issuecomment-798050828
|
||||
sqlx = { version = "0.7.2", features = [ "mysql", "runtime-tokio", "tls-rustls", "chrono" ] }
|
||||
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
[dev-dependencies]
|
||||
# None yet
|
||||
|
||||
@@ -14,7 +14,7 @@ path = "src/lib.rs"
|
||||
|
||||
[dependencies]
|
||||
# External
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
[dev-dependencies]
|
||||
serial_test = "2.0.0"
|
||||
|
||||
@@ -15,7 +15,7 @@ path = "src/lib.rs"
|
||||
[dependencies]
|
||||
|
||||
# External
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
# Serialization
|
||||
#serde = "1.0.125"
|
||||
|
||||
@@ -18,7 +18,7 @@ path = "src/lib.rs"
|
||||
|
||||
# Internal
|
||||
errors = { path = "../errors" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
# External
|
||||
# None yet
|
||||
|
||||
@@ -20,7 +20,7 @@ user_input_common = { path = "../user_input_common" }
|
||||
|
||||
# External
|
||||
anyhow = "1.0.75"
|
||||
chrono = { version = "=0.4.22", features = ["serde"] }
|
||||
chrono = { version = "0.4.22", features = ["serde"] }
|
||||
log = "0.4.14"
|
||||
once_cell = "1.18.0"
|
||||
regex = "1.5.4"
|
||||
@@ -29,4 +29,4 @@ unicode-segmentation = "1.10.1"
|
||||
# Serialization
|
||||
serde = "1.0.125"
|
||||
serde_derive = "1.0.125"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
@@ -21,4 +21,4 @@ reusable_types = { path = "../../_types/reusable_types" }
|
||||
# External
|
||||
actix-web = "4.4.0"
|
||||
anyhow = "1.0.75"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
@@ -19,4 +19,4 @@ once_cell = "1.18.0"
|
||||
pulldown-cmark = "0.9.3" # Markdown
|
||||
regex = "1.5.4"
|
||||
unicode-segmentation = "1.10.1"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
@@ -19,7 +19,7 @@ errors = { path = "../../lib/errors" }
|
||||
|
||||
# External
|
||||
bytes = "1.3"
|
||||
chrono = { version = "=0.4.22", features = ["serde"] }
|
||||
chrono = { version = "0.4.22", features = ["serde"] }
|
||||
log = "0.4.14"
|
||||
once_cell = "1.18.0"
|
||||
strum = { version = "0.25", features = ["derive"] } # Fancy enum iteration, etc.
|
||||
@@ -35,7 +35,7 @@ reqwest = { version = "0.11", features = ["json"] } # HTTP Client
|
||||
# Scraping
|
||||
rss = "2.0.2"
|
||||
scraper = "0.17.1"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../my-workspace-hack" }
|
||||
|
||||
[dev-dependencies]
|
||||
# None yet
|
||||
|
||||
@@ -142,22 +142,22 @@ url = { version = "2.4.1", features = ["serde"] }
|
||||
[target.x86_64-unknown-linux-gnu.dependencies]
|
||||
openssl = { version = "0.10.59", features = ["vendored"] }
|
||||
openssl-sys = { version = "0.9.95", default-features = false, features = ["vendored"] }
|
||||
rustix = { version = "0.38.25", features = ["fs", "termios"] }
|
||||
rustix = { version = "0.38.26", features = ["fs", "termios"] }
|
||||
spin = { version = "0.9.8" }
|
||||
|
||||
[target.x86_64-unknown-linux-gnu.build-dependencies]
|
||||
openssl = { version = "0.10.59", features = ["vendored"] }
|
||||
openssl-sys = { version = "0.9.95", default-features = false, features = ["vendored"] }
|
||||
rustix = { version = "0.38.25", features = ["fs", "termios"] }
|
||||
rustix = { version = "0.38.26", features = ["fs", "termios"] }
|
||||
socket2 = { version = "0.5.5", default-features = false, features = ["all"] }
|
||||
spin = { version = "0.9.8" }
|
||||
|
||||
[target.x86_64-apple-darwin.dependencies]
|
||||
rustix = { version = "0.38.25", features = ["fs", "termios"] }
|
||||
rustix = { version = "0.38.26", features = ["fs", "termios"] }
|
||||
spin = { version = "0.9.8" }
|
||||
|
||||
[target.x86_64-apple-darwin.build-dependencies]
|
||||
rustix = { version = "0.38.25", features = ["fs", "termios"] }
|
||||
rustix = { version = "0.38.26", features = ["fs", "termios"] }
|
||||
socket2 = { version = "0.5.5", default-features = false, features = ["all"] }
|
||||
spin = { version = "0.9.8" }
|
||||
|
||||
@@ -32,7 +32,7 @@ web_scrapers = { path = "../../lib/web_scrapers" }
|
||||
|
||||
# External
|
||||
base64 = "0.21.0"
|
||||
chrono = { version = "=0.4.22", features = ["serde"] }
|
||||
chrono = { version = "0.4.22", features = ["serde"] }
|
||||
clap = "2.34.0" # TODO: This is really out of date, but has conflicts when updated
|
||||
dotenv = "0.15.0"
|
||||
log = "0.4.14"
|
||||
@@ -42,11 +42,6 @@ rand = "0.8.3"
|
||||
regex = "1.5.4"
|
||||
strum = { version = "0.24", features = ["derive"] } # Fancy enum iteration, etc.
|
||||
|
||||
# SQlite Database
|
||||
# "offline" supports typesafe builds without a live database
|
||||
# "rustls" doesn't appear to work with IP addresses, per:
|
||||
# https://github.com/launchbadge/sqlx/issues/1095#issuecomment-798050828
|
||||
# ^^^ Granted, this applies to *MySQL* and probably not SQLite for our use case here ^^^
|
||||
sqlx = { version = "0.7.2", features = [ "sqlite", "runtime-tokio-native-tls", "chrono" ] }
|
||||
|
||||
# Async Runtime
|
||||
|
||||
@@ -26,16 +26,12 @@ tokens = { path = "../../../_types/tokens" }
|
||||
|
||||
# External
|
||||
anyhow = "1.0.75"
|
||||
chrono = { version = "=0.4.22", features = ["serde"] }
|
||||
chrono = { version = "0.4.22", features = ["serde"] }
|
||||
dotenv = "0.15.0"
|
||||
hostname = "0.3.1"
|
||||
log = "0.4.14"
|
||||
rand = "0.8.5"
|
||||
|
||||
# MySql Database
|
||||
# "offline" supports typesafe builds without a live database
|
||||
# "rustls" doesn't appear to work with IP addresses, per:
|
||||
# https://github.com/launchbadge/sqlx/issues/1095#issuecomment-798050828
|
||||
sqlx = { version = "0.7.2", features = [ "mysql", "runtime-tokio", "tls-rustls", "chrono" ] }
|
||||
|
||||
# Runtime
|
||||
@@ -46,4 +42,4 @@ tokio = { version = "1.6.0", features = ["macros"] }
|
||||
serde = "1.0.125"
|
||||
serde_derive = "1.0.125"
|
||||
serde_json = "1.0.108"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
|
||||
@@ -35,7 +35,7 @@ subprocess_common = { path = "../../../lib/subprocess_common" }
|
||||
|
||||
# External
|
||||
anyhow = "1.0.75"
|
||||
chrono = { version = "=0.4.22", features = ["serde"] }
|
||||
chrono = { version = "0.4.22", features = ["serde"] }
|
||||
dotenv = "0.15.0"
|
||||
hostname = "0.3.1"
|
||||
log = "0.4.14"
|
||||
@@ -43,10 +43,6 @@ subprocess = "0.2.9"
|
||||
tempdir = "0.3.7"
|
||||
zip = "0.6.6"
|
||||
|
||||
# MySql Database
|
||||
# "offline" supports typesafe builds without a live database
|
||||
# "rustls" doesn't appear to work with IP addresses, per:
|
||||
# https://github.com/launchbadge/sqlx/issues/1095#issuecomment-798050828
|
||||
sqlx = { version = "0.7.2", features = [ "mysql", "runtime-tokio", "tls-rustls", "chrono" ] }
|
||||
|
||||
# Redis
|
||||
@@ -64,4 +60,4 @@ hyper = { version = "0.14.24" }
|
||||
serde = "1.0.125"
|
||||
serde_derive = "1.0.125"
|
||||
serde_json = "1.0.108"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
|
||||
@@ -46,7 +46,7 @@ tts_common = { path = "../../../lib/tts_common" }
|
||||
|
||||
# External
|
||||
anyhow = "1.0.75"
|
||||
chrono = { version = "=0.4.22", features = ["serde"] }
|
||||
chrono = { version = "0.4.22", features = ["serde"] }
|
||||
clap = "2.34.0" # TODO: This is really out of date, but has conflicts when updated
|
||||
dotenv = "0.15.0"
|
||||
hostname = "0.3.1"
|
||||
@@ -56,10 +56,6 @@ once_cell = "1.18.0"
|
||||
subprocess = "0.2.9"
|
||||
tempdir = "0.3.7"
|
||||
|
||||
# MySql Database
|
||||
# "offline" supports typesafe builds without a live database
|
||||
# "rustls" doesn't appear to work with IP addresses, per:
|
||||
# https://github.com/launchbadge/sqlx/issues/1095#issuecomment-798050828
|
||||
sqlx = { version = "0.7.2", features = [ "mysql", "runtime-tokio", "tls-rustls", "chrono" ] }
|
||||
|
||||
# Redis
|
||||
@@ -86,4 +82,4 @@ serde_json = "1.0.108"
|
||||
# The initial round of stabilizations for the async/await language feature in Rust 1.39 did not
|
||||
# include support for async fn in traits.
|
||||
async-trait = "0.1.58"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
|
||||
@@ -43,7 +43,7 @@ newrelic-telemetry = { path = "../../../vendor/newrelic-telemetry-sdk-rust" }
|
||||
|
||||
# External
|
||||
anyhow = "1.0.75"
|
||||
chrono = { version = "=0.4.22", features = ["serde"] }
|
||||
chrono = { version = "0.4.22", features = ["serde"] }
|
||||
dotenv = "0.15.0"
|
||||
hostname = "0.3.1"
|
||||
lfu = "0.2.5"
|
||||
@@ -52,10 +52,6 @@ once_cell = "1.18.0"
|
||||
subprocess = "0.2.9"
|
||||
tempdir = "0.3.7"
|
||||
|
||||
# MySql Database
|
||||
# "offline" supports typesafe builds without a live database
|
||||
# "rustls" doesn't appear to work with IP addresses, per:
|
||||
# https://github.com/launchbadge/sqlx/issues/1095#issuecomment-798050828
|
||||
sqlx = { version = "0.7.2", features = [ "mysql", "runtime-tokio", "tls-rustls", "chrono" ] }
|
||||
|
||||
# Redis
|
||||
@@ -82,4 +78,4 @@ serde_json = "1.0.108"
|
||||
# The initial round of stabilizations for the async/await language feature in Rust 1.39 did not
|
||||
# include support for async fn in traits.
|
||||
async-trait = "0.1.58"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
|
||||
+1
@@ -8,5 +8,6 @@ pub mod tacotron2_dependencies;
|
||||
pub mod tacotron2_inference_command;
|
||||
pub mod tacotron2_inference_sidecar_client;
|
||||
pub mod tacotron2_sidecar_health_check_client;
|
||||
pub mod upload_results;
|
||||
pub mod virtual_lfu_cache;
|
||||
pub mod vocoder_option;
|
||||
|
||||
+20
-70
@@ -27,6 +27,7 @@ use crate::job::job_types::tts::tacotron2_v2_early_fakeyou::download_static_depe
|
||||
use crate::job::job_types::tts::tacotron2_v2_early_fakeyou::health_check_trap::maybe_block_on_sidecar_health_check;
|
||||
use crate::job::job_types::tts::tacotron2_v2_early_fakeyou::seconds_to_decoder_steps::seconds_to_decoder_steps;
|
||||
use crate::job::job_types::tts::tacotron2_v2_early_fakeyou::tacotron2_inference_command::{InferenceArgs, MelMultiplyFactor};
|
||||
use crate::job::job_types::tts::tacotron2_v2_early_fakeyou::upload_results::{upload_results, UploadResultArgs};
|
||||
use crate::job::job_types::tts::tacotron2_v2_early_fakeyou::vocoder_option::VocoderForInferenceOption;
|
||||
use crate::job_dependencies::JobDependencies;
|
||||
use crate::util::maybe_download_file_from_bucket::{maybe_download_file_from_bucket, MaybeDownloadArgs};
|
||||
@@ -305,78 +306,27 @@ async fn process_job_with_cleanup(
|
||||
|
||||
safe_delete_temp_file(&output_metadata_fs_path);
|
||||
|
||||
// ==================== UPLOAD AUDIO TO BUCKET ==================== //
|
||||
// ==================== UPLOAD FILES AND SAVE RECORD ==================== //
|
||||
|
||||
job_progress_reporter.log_status("uploading result")
|
||||
.map_err(|e| ProcessSingleJobError::Other(e))?;
|
||||
|
||||
let audio_result_object_path = args.job_dependencies.buckets.bucket_path_unifier.tts_inference_wav_audio_output_path(
|
||||
&job.uuid_idempotency_token); // TODO: Don't use this!
|
||||
|
||||
info!("Audio destination bucket path: {:?}", &audio_result_object_path);
|
||||
|
||||
info!("Uploading audio...");
|
||||
|
||||
args.job_dependencies.buckets.public_bucket_client.upload_filename_with_content_type(
|
||||
&audio_result_object_path,
|
||||
&output_audio_fs_path,
|
||||
"audio/wav")
|
||||
.await
|
||||
.map_err(|e| ProcessSingleJobError::Other(e))?;
|
||||
|
||||
safe_delete_temp_file(&output_audio_fs_path);
|
||||
|
||||
// ==================== UPLOAD SPECTROGRAM TO BUCKETS ==================== //
|
||||
|
||||
let spectrogram_result_object_path = args.job_dependencies.buckets.bucket_path_unifier.tts_inference_spectrogram_output_path(
|
||||
&job.uuid_idempotency_token); // TODO: Don't use this!
|
||||
|
||||
info!("Spectrogram destination bucket path: {:?}", &spectrogram_result_object_path);
|
||||
|
||||
info!("Uploading spectrogram...");
|
||||
|
||||
args.job_dependencies.buckets.public_bucket_client.upload_filename_with_content_type(
|
||||
&spectrogram_result_object_path,
|
||||
&output_spectrogram_fs_path,
|
||||
"application/json")
|
||||
.await
|
||||
.map_err(|e| ProcessSingleJobError::Other(e))?;
|
||||
|
||||
safe_delete_temp_file(&output_spectrogram_fs_path);
|
||||
|
||||
// ==================== DELETE DOWNLOADED FILE ==================== //
|
||||
|
||||
// NB: We should be using a tempdir, but to make absolutely certain we don't overflow the disk...
|
||||
safe_delete_temp_directory(&work_temp_dir.path());
|
||||
|
||||
// ==================== SAVE RECORDS ==================== //
|
||||
|
||||
let text_hash = sha256_hash_string(&cleaned_inference_text)
|
||||
.map_err(|e| ProcessSingleJobError::Other(e))?;
|
||||
|
||||
info!("Saving tts inference record...");
|
||||
|
||||
let (id, inference_result_token) = insert_tts_result(
|
||||
&args.job_dependencies.db.mysql_pool,
|
||||
JobType::GenericInferenceJob(&job),
|
||||
&text_hash,
|
||||
Some(pretrained_vocoder),
|
||||
&audio_result_object_path,
|
||||
&spectrogram_result_object_path,
|
||||
file_metadata.file_size_bytes,
|
||||
file_metadata.duration_millis.unwrap_or(0),
|
||||
args.job_dependencies.job.info.container.is_on_prem,
|
||||
&args.job_dependencies.job.info.container.hostname,
|
||||
args.job_dependencies.job.system.is_debug_worker)
|
||||
.await
|
||||
.map_err(|e| ProcessSingleJobError::Other(e))?;
|
||||
let inference_result = upload_results(UploadResultArgs {
|
||||
job_dependencies: args.job_dependencies,
|
||||
job_progress_reporter: &mut job_progress_reporter,
|
||||
job,
|
||||
cleaned_inference_text: &cleaned_inference_text,
|
||||
work_temp_dir,
|
||||
pretrained_vocoder,
|
||||
file_metadata: &file_metadata,
|
||||
output_audio_fs_path: &output_audio_fs_path,
|
||||
output_spectrogram_fs_path: &output_spectrogram_fs_path,
|
||||
upload_as_media_file: model_dependencies.upload_as_media_file,
|
||||
}).await?;
|
||||
|
||||
info!("TTS Done. Original text was: {:?}", &job.maybe_raw_inference_text);
|
||||
|
||||
args.job_dependencies.clients.firehose_publisher.tts_inference_finished(
|
||||
job.maybe_creator_user_token.as_deref(),
|
||||
tts_model.model_token.as_str(),
|
||||
&inference_result_token)
|
||||
&inference_result.entity_token)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
error!("error publishing event: {:?}", e);
|
||||
@@ -386,20 +336,20 @@ async fn process_job_with_cleanup(
|
||||
job_progress_reporter.log_status("done")
|
||||
.map_err(|e| ProcessSingleJobError::Other(e))?;
|
||||
|
||||
info!("Job {:?} complete success! Downloaded, ran inference, and uploaded. Saved model record: {}, Result Token: {}",
|
||||
job.id, id, &inference_result_token);
|
||||
info!("Job {:?} complete success! Downloaded, ran inference, and uploaded. Result Token: {}",
|
||||
job.id, &inference_result.entity_token);
|
||||
|
||||
Ok(JobSuccessResult {
|
||||
maybe_result_entity: Some(ResultEntity {
|
||||
entity_type: InferenceResultType::TextToSpeech,
|
||||
entity_token: inference_result_token
|
||||
entity_type: inference_result.entity_type,
|
||||
entity_token: inference_result.entity_token,
|
||||
}),
|
||||
inference_duration,
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
struct FileMetadata {
|
||||
pub struct FileMetadata {
|
||||
pub duration_millis: Option<u64>,
|
||||
pub mimetype: Option<String>,
|
||||
pub file_size_bytes: u64,
|
||||
|
||||
+4
-1
@@ -20,6 +20,8 @@ pub struct Tacotron2Dependencies {
|
||||
|
||||
/// Dependencies that are for the sidecar version of TT2
|
||||
pub sidecar: SidecarDeps,
|
||||
|
||||
pub upload_as_media_file: bool,
|
||||
}
|
||||
|
||||
pub struct SidecarDeps {
|
||||
@@ -71,7 +73,8 @@ impl Tacotron2Dependencies {
|
||||
health_check_client,
|
||||
health_check_state: HealthCheckState::new(),
|
||||
virtual_lfu_cache,
|
||||
}
|
||||
},
|
||||
upload_as_media_file: easyenv::get_env_bool_or_default("TT2_AS_MEDIA_FILES", false),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
+202
@@ -0,0 +1,202 @@
|
||||
use std::path::Path;
|
||||
use anyhow::anyhow;
|
||||
|
||||
use log::info;
|
||||
use tempdir::TempDir;
|
||||
use buckets::public::media_files::original_file::MediaFileBucketPath;
|
||||
|
||||
use cloud_storage::bucket_path_unifier::BucketPathUnifier;
|
||||
use enums::by_table::generic_inference_jobs::inference_result_type::InferenceResultType;
|
||||
use filesys::safe_delete_temp_directory::safe_delete_temp_directory;
|
||||
use filesys::safe_delete_temp_file::safe_delete_temp_file;
|
||||
use hashing::sha256::sha256_hash_file::sha256_hash_file;
|
||||
use hashing::sha256::sha256_hash_string::sha256_hash_string;
|
||||
use jobs_common::job_progress_reporter::job_progress_reporter::JobProgressReporter;
|
||||
use mysql_queries::column_types::vocoder_type::VocoderType;
|
||||
use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob;
|
||||
use mysql_queries::queries::media_files::insert_media_file_from_tacotron2::{insert_media_file_from_tacotron2, InsertMediaFileArgs};
|
||||
use mysql_queries::queries::tts::tts_results::insert_tts_result::JobType;
|
||||
use mysql_queries::queries::tts::tts_results::insert_tts_result::insert_tts_result;
|
||||
|
||||
use crate::job::job_loop::process_single_job_error::ProcessSingleJobError;
|
||||
use crate::job::job_types::tts::tacotron2_v2_early_fakeyou::process_job::FileMetadata;
|
||||
use crate::job_dependencies::JobDependencies;
|
||||
|
||||
const BUCKET_FILE_PREFIX: &str = "fakeyou_";
|
||||
const BUCKET_FILE_EXTENSION: &str = ".wav";
|
||||
const MIME_TYPE: &str = "audio/wav";
|
||||
|
||||
pub struct UploadResultArgs<'a> {
|
||||
// System
|
||||
pub job_dependencies: &'a JobDependencies,
|
||||
pub job_progress_reporter: &'a mut Box<dyn JobProgressReporter>,
|
||||
|
||||
// Job
|
||||
pub job: &'a AvailableInferenceJob,
|
||||
pub cleaned_inference_text: &'a str,
|
||||
pub work_temp_dir: &'a TempDir,
|
||||
pub pretrained_vocoder: VocoderType,
|
||||
|
||||
// Outputs
|
||||
pub file_metadata: &'a FileMetadata,
|
||||
pub output_audio_fs_path: &'a Path,
|
||||
pub output_spectrogram_fs_path: &'a Path,
|
||||
|
||||
// Flags
|
||||
pub upload_as_media_file: bool,
|
||||
}
|
||||
|
||||
pub struct ResultDetails {
|
||||
pub entity_type: InferenceResultType,
|
||||
pub entity_token: String,
|
||||
}
|
||||
|
||||
pub async fn upload_results(args: UploadResultArgs<'_>) -> Result<ResultDetails, ProcessSingleJobError>{
|
||||
if args.upload_as_media_file {
|
||||
upload_as_media_file(args).await
|
||||
} else {
|
||||
upload_as_legacy_tts_result(args).await
|
||||
}
|
||||
}
|
||||
|
||||
async fn upload_as_media_file(args: UploadResultArgs<'_>) -> Result<ResultDetails, ProcessSingleJobError>{
|
||||
|
||||
// ==================== UPLOAD AUDIO TO BUCKET ==================== //
|
||||
|
||||
args.job_progress_reporter.log_status("uploading result")
|
||||
.map_err(|e| ProcessSingleJobError::Other(e))?;
|
||||
|
||||
let result_bucket_location = MediaFileBucketPath::generate_new(
|
||||
Some(BUCKET_FILE_PREFIX),
|
||||
Some(BUCKET_FILE_EXTENSION)
|
||||
);
|
||||
|
||||
let result_bucket_object_pathbuf = result_bucket_location.to_full_object_pathbuf();
|
||||
|
||||
info!("Audio destination bucket path: {:?}", &result_bucket_location.to_full_object_pathbuf());
|
||||
|
||||
info!("Uploading audio...");
|
||||
|
||||
args.job_dependencies.buckets.public_bucket_client.upload_filename_with_content_type(
|
||||
&result_bucket_object_pathbuf,
|
||||
&args.output_audio_fs_path,
|
||||
"audio/wav")
|
||||
.await
|
||||
.map_err(|e| ProcessSingleJobError::Other(e))?;
|
||||
|
||||
let file_checksum = sha256_hash_file(&args.output_audio_fs_path).map_err(|err| {
|
||||
ProcessSingleJobError::Other(anyhow!("Error hashing file: {:?}", err))
|
||||
})?;
|
||||
|
||||
safe_delete_temp_file(&args.output_audio_fs_path);
|
||||
|
||||
// ==================== UPLOAD SPECTROGRAM TO BUCKETS ==================== //
|
||||
|
||||
// (SKIP FOR NOW)
|
||||
|
||||
// ==================== DELETE WORK DIRECTORY ==================== //
|
||||
|
||||
// NB: We should be using a tempdir, but to make absolutely certain we don't overflow the disk...
|
||||
safe_delete_temp_directory(&args.work_temp_dir.path());
|
||||
|
||||
// ==================== SAVE RECORDS ==================== //
|
||||
|
||||
info!("Saving tts inference record...");
|
||||
|
||||
let (inference_result_token, _id) = insert_media_file_from_tacotron2(InsertMediaFileArgs {
|
||||
pool: &args.job_dependencies.db.mysql_pool,
|
||||
job: &args.job,
|
||||
maybe_mime_type: Some(&MIME_TYPE),
|
||||
file_size_bytes: args.file_metadata.file_size_bytes,
|
||||
duration_millis: args.file_metadata.duration_millis.unwrap_or(0),
|
||||
sha256_checksum: &file_checksum,
|
||||
public_bucket_directory_hash: result_bucket_location.get_object_hash(),
|
||||
maybe_public_bucket_prefix: Some(BUCKET_FILE_PREFIX),
|
||||
maybe_public_bucket_extension: Some(BUCKET_FILE_EXTENSION),
|
||||
is_on_prem: args.job_dependencies.job.info.container.is_on_prem,
|
||||
worker_hostname: &args.job_dependencies.job.info.container.hostname,
|
||||
worker_cluster: &args.job_dependencies.job.info.container.cluster_name,
|
||||
})
|
||||
.await
|
||||
.map_err(|e| ProcessSingleJobError::Other(e))?;
|
||||
|
||||
Ok(ResultDetails {
|
||||
entity_type: InferenceResultType::MediaFile,
|
||||
entity_token: inference_result_token.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
async fn upload_as_legacy_tts_result(args: UploadResultArgs<'_>) -> Result<ResultDetails, ProcessSingleJobError>{
|
||||
|
||||
// ==================== UPLOAD AUDIO TO BUCKET ==================== //
|
||||
|
||||
args.job_progress_reporter.log_status("uploading result")
|
||||
.map_err(|e| ProcessSingleJobError::Other(e))?;
|
||||
|
||||
let audio_result_object_path = args.job_dependencies.buckets.bucket_path_unifier.tts_inference_wav_audio_output_path(
|
||||
&args.job.uuid_idempotency_token); // TODO: Don't use this!
|
||||
|
||||
info!("Audio destination bucket path: {:?}", &audio_result_object_path);
|
||||
|
||||
info!("Uploading audio...");
|
||||
|
||||
args.job_dependencies.buckets.public_bucket_client.upload_filename_with_content_type(
|
||||
&audio_result_object_path,
|
||||
&args.output_audio_fs_path,
|
||||
"audio/wav")
|
||||
.await
|
||||
.map_err(|e| ProcessSingleJobError::Other(e))?;
|
||||
|
||||
safe_delete_temp_file(&args.output_audio_fs_path);
|
||||
|
||||
// ==================== UPLOAD SPECTROGRAM TO BUCKETS ==================== //
|
||||
|
||||
let spectrogram_result_object_path = args.job_dependencies.buckets.bucket_path_unifier.tts_inference_spectrogram_output_path(
|
||||
&args.job.uuid_idempotency_token); // TODO: Don't use this!
|
||||
|
||||
info!("Spectrogram destination bucket path: {:?}", &spectrogram_result_object_path);
|
||||
|
||||
info!("Uploading spectrogram...");
|
||||
|
||||
args.job_dependencies.buckets.public_bucket_client.upload_filename_with_content_type(
|
||||
&spectrogram_result_object_path,
|
||||
&args.output_spectrogram_fs_path,
|
||||
"application/json")
|
||||
.await
|
||||
.map_err(|e| ProcessSingleJobError::Other(e))?;
|
||||
|
||||
safe_delete_temp_file(&args.output_spectrogram_fs_path);
|
||||
|
||||
// ==================== DELETE WORK DIRECTORY ==================== //
|
||||
|
||||
// NB: We should be using a tempdir, but to make absolutely certain we don't overflow the disk...
|
||||
safe_delete_temp_directory(&args.work_temp_dir.path());
|
||||
|
||||
// ==================== SAVE RECORDS ==================== //
|
||||
|
||||
let text_hash = sha256_hash_string(&args.cleaned_inference_text)
|
||||
.map_err(|e| ProcessSingleJobError::Other(e))?;
|
||||
|
||||
info!("Saving tts inference record...");
|
||||
|
||||
let (_id, inference_result_token) = insert_tts_result(
|
||||
&args.job_dependencies.db.mysql_pool,
|
||||
JobType::GenericInferenceJob(&args.job),
|
||||
&text_hash,
|
||||
Some(args.pretrained_vocoder),
|
||||
&audio_result_object_path,
|
||||
&spectrogram_result_object_path,
|
||||
args.file_metadata.file_size_bytes,
|
||||
args.file_metadata.duration_millis.unwrap_or(0),
|
||||
args.job_dependencies.job.info.container.is_on_prem,
|
||||
&args.job_dependencies.job.info.container.hostname,
|
||||
args.job_dependencies.job.system.is_debug_worker)
|
||||
.await
|
||||
.map_err(|e| ProcessSingleJobError::Other(e))?;
|
||||
|
||||
Ok(ResultDetails {
|
||||
entity_type: InferenceResultType::TextToSpeech,
|
||||
entity_token: inference_result_token,
|
||||
})
|
||||
}
|
||||
+1
-1
@@ -23,7 +23,6 @@ use crate::job::job_loop::process_single_job_error::ProcessSingleJobError;
|
||||
use crate::job::job_types::tts::vall_e_x::process_job::VALLEXProcessJobArgs;
|
||||
use crate::job::job_types::tts::vall_e_x::vall_e_x_inference_command::InferenceArgs;
|
||||
|
||||
// Clearify what this is for ?
|
||||
const BUCKET_FILE_PREFIX: &str = "fakeyou_";
|
||||
const BUCKET_FILE_EXTENSION: &str = ".wav";
|
||||
const MIME_TYPE: &str = "audio/wav";
|
||||
@@ -208,6 +207,7 @@ pub async fn process_inference_voice(
|
||||
.map_err(|e| ProcessSingleJobError::Other(e))?;
|
||||
|
||||
// ==================== UPLOAD AUDIO TO BUCKET ====================
|
||||
|
||||
info!("Calculating sha256...");
|
||||
|
||||
let file_checksum = sha256_hash_file(&finished_file).map_err(|err| {
|
||||
|
||||
@@ -28,17 +28,13 @@ mysql_queries = { path = "../../../lib/mysql_queries" }
|
||||
|
||||
# External
|
||||
anyhow = "1.0.75"
|
||||
chrono = { version = "=0.4.22", features = ["serde"] }
|
||||
chrono = { version = "0.4.22", features = ["serde"] }
|
||||
dotenv = "0.15.0"
|
||||
hostname = "0.3.1"
|
||||
log = "0.4.14"
|
||||
subprocess = "0.2.9"
|
||||
tempdir = "0.3.7"
|
||||
|
||||
# MySql Database
|
||||
# "offline" supports typesafe builds without a live database
|
||||
# "rustls" doesn't appear to work with IP addresses, per:
|
||||
# https://github.com/launchbadge/sqlx/issues/1095#issuecomment-798050828
|
||||
sqlx = { version = "0.7.2", features = [ "mysql", "runtime-tokio", "tls-rustls", "chrono" ] }
|
||||
|
||||
# Redis
|
||||
@@ -56,4 +52,4 @@ hyper = { version = "0.14.24" }
|
||||
serde = "1.0.125"
|
||||
serde_derive = "1.0.125"
|
||||
serde_json = "1.0.108"
|
||||
my-workspace-hack = { version = "0.1", path = "../../../../my-workspace-hack" }
|
||||
my-workspace-hack = { version = "0.1", path = "../../../my-workspace-hack" }
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user