mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-15 06:12:18 +00:00
truncate audio
This commit is contained in:
1 parent
7f95c86e31
commit
2ee6822bac
7 files changed
+72
-92
No files matched your search
-32
@@ -154,38 +154,6 @@ impl GenericInferenceArgs {
|
||||
}
|
||||
}
|
||||
|
||||
//impl InferenceCategoryAbbreviated {
|
||||
// pub fn from_inference_category(category: InferenceCategory) -> Self {
|
||||
// match category {
|
||||
// InferenceCategory::LipsyncAnimation => Self::LipsyncAnimation,
|
||||
// InferenceCategory::TextToSpeech => Self::TextToSpeech,
|
||||
// InferenceCategory::VoiceConversion => Self::VoiceConversion,
|
||||
// InferenceCategory::VideoFilter => Self::VideoFilter,
|
||||
// InferenceCategory::ImageGeneration => Self::ImageGeneration,
|
||||
// InferenceCategory::Mocap => Self::Mocap,
|
||||
// InferenceCategory::Workflow => Self::Workflow,
|
||||
// InferenceCategory::FormatConversion => Self::FormatConversion,
|
||||
// InferenceCategory::ConvertBvhToWorkflow => Self::ConvertBvhToWorkflow,
|
||||
// InferenceCategory::DeprecatedField => Self::LivePortrait, // TODO(bt,2024-07-16): This isn't correct
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// pub fn to_inference_category(self) -> InferenceCategory {
|
||||
// match self {
|
||||
// Self::LipsyncAnimation => InferenceCategory::LipsyncAnimation,
|
||||
// Self::TextToSpeech => InferenceCategory::TextToSpeech,
|
||||
// Self::VoiceConversion => InferenceCategory::VoiceConversion,
|
||||
// Self::VideoFilter => InferenceCategory::VideoFilter,
|
||||
// Self::ImageGeneration =>InferenceCategory::ImageGeneration,
|
||||
// Self::Mocap => InferenceCategory::Mocap,
|
||||
// Self::Workflow => InferenceCategory::Workflow,
|
||||
// Self::LivePortrait => InferenceCategory::DeprecatedField, // TODO(bt,2024-07-16): This isn't correct
|
||||
// Self::FormatConversion => InferenceCategory::FormatConversion,
|
||||
// Self::ConvertBvhToWorkflow => InferenceCategory::ConvertBvhToWorkflow,
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use tokens::tokens::{media_files::MediaFileToken, model_weights::ModelWeightToken};
|
||||
|
||||
@@ -13,5 +13,16 @@ pub struct GptSovitsPayload {
|
||||
#[serde(rename = "cv")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub creator_visibility: Option<Visibility>,
|
||||
|
||||
// For free users, we may truncate long TTS inferences.
|
||||
#[serde(rename = "s")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub truncate_seconds: Option<u64>,
|
||||
|
||||
// For free users, we may occasionally append an advertisement
|
||||
// to sign in or upgrade.
|
||||
#[serde(rename = "a")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub append_advertisement: Option<bool>,
|
||||
}
|
||||
|
||||
+3
@@ -1,9 +1,11 @@
|
||||
use errors::AnyhowResult;
|
||||
|
||||
use crate::job::job_types::gpt_sovits::gpt_sovits_inference_command::GptSovitsInferenceCommand;
|
||||
use crate::util::common_commands::ffmpeg::runner::ffmpeg_command_runner::FfmpegCommandRunner;
|
||||
|
||||
pub struct GptSovitsDependencies {
|
||||
pub inference_command: GptSovitsInferenceCommand,
|
||||
pub ffmpeg_command_runner: FfmpegCommandRunner,
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +13,7 @@ impl GptSovitsDependencies {
|
||||
pub fn setup() -> AnyhowResult<Self> {
|
||||
Ok(Self {
|
||||
inference_command: GptSovitsInferenceCommand::from_env()?,
|
||||
ffmpeg_command_runner: FfmpegCommandRunner::from_env()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
+19
-24
@@ -1,6 +1,6 @@
|
||||
use anyhow::anyhow;
|
||||
|
||||
use mysql_queries::payloads::generic_inference_args::generic_inference_args::InferenceCategoryAbbreviated;
|
||||
use mysql_queries::payloads::generic_inference_args::generic_inference_args::{InferenceCategoryAbbreviated, PolymorphicInferenceArgs};
|
||||
use mysql_queries::queries::generic_inference::job::list_available_generic_inference_jobs::AvailableInferenceJob;
|
||||
use tokens::tokens::model_weights::ModelWeightToken;
|
||||
|
||||
@@ -13,14 +13,11 @@ pub struct JobArgs {
|
||||
pub reference_free: Option<bool>,
|
||||
pub temperature: Option<f32>,
|
||||
pub target_language: Option<String>,
|
||||
pub maybe_truncate_seconds: Option<u64>,
|
||||
pub maybe_append_advertisement: Option<bool>,
|
||||
}
|
||||
|
||||
pub fn check_and_validate_job(job: &AvailableInferenceJob) -> Result<JobArgs, ProcessSingleJobError> {
|
||||
let inference_args = job.maybe_inference_args
|
||||
.as_ref()
|
||||
.map(|args| args.args.as_ref())
|
||||
.flatten();
|
||||
|
||||
let inference_category = job.maybe_inference_args
|
||||
.as_ref()
|
||||
.map(|args| args.inference_category)
|
||||
@@ -34,20 +31,17 @@ pub fn check_and_validate_job(job: &AvailableInferenceJob) -> Result<JobArgs, Pr
|
||||
}
|
||||
};
|
||||
|
||||
// let inference_args = match inference_args {
|
||||
// Some(args) => args,
|
||||
// None => {
|
||||
// return Err(ProcessSingleJobError::from_anyhow_error(anyhow!("no inference args for job!")));
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// let inference_args = match inference_args {
|
||||
// PolymorphicInferenceArgs::Gs(inference_args) => inference_args,
|
||||
// _ => {
|
||||
// return Err(ProcessSingleJobError::from_anyhow_error(anyhow!("wrong inner args for job!")));
|
||||
// }
|
||||
// };
|
||||
//
|
||||
let inference_args = job.maybe_inference_args
|
||||
.as_ref()
|
||||
.map(|args| args.args.as_ref())
|
||||
.flatten()
|
||||
.map(|args| match args {
|
||||
PolymorphicInferenceArgs::Gs(args) => Ok(args),
|
||||
_ => Err(ProcessSingleJobError::from_anyhow_error(anyhow!("wrong payload for job!"))),
|
||||
})
|
||||
.transpose()?
|
||||
.ok_or_else(|| ProcessSingleJobError::from_anyhow_error(anyhow!("no inference args for job!")))?;
|
||||
|
||||
let input_text = match &job.maybe_raw_inference_text {
|
||||
Some(text) => text.clone(),
|
||||
None => {
|
||||
@@ -62,12 +56,13 @@ pub fn check_and_validate_job(job: &AvailableInferenceJob) -> Result<JobArgs, Pr
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Ok(JobArgs {
|
||||
input_text: input_text,
|
||||
gpt_sovits_model: gpt_sovits_model,
|
||||
input_text,
|
||||
gpt_sovits_model,
|
||||
reference_free: None,
|
||||
temperature: None,
|
||||
target_language: None,
|
||||
maybe_truncate_seconds: inference_args.truncate_seconds.clone(),
|
||||
maybe_append_advertisement: inference_args.append_advertisement.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
+37
-19
@@ -11,6 +11,7 @@ use enums::by_table::generic_inference_jobs::inference_result_type::InferenceRes
|
||||
use enums::by_table::media_files::media_file_origin_model_type::MediaFileOriginModelType;
|
||||
use enums::by_table::media_files::media_file_type::MediaFileType;
|
||||
use filesys::check_file_exists::check_file_exists;
|
||||
use filesys::file_exists::file_exists;
|
||||
use filesys::file_size::file_size;
|
||||
use hashing::sha256::sha256_hash_file::sha256_hash_file;
|
||||
use media::decode_basic_audio_info::decode_basic_audio_file_info;
|
||||
@@ -27,6 +28,7 @@ use crate::job::job_types::gpt_sovits::model_package::model_package::GptSovitsPa
|
||||
use crate::job::job_types::gpt_sovits::tts_inference::check_and_validate_job::check_and_validate_job;
|
||||
use crate::state::job_dependencies::JobDependencies;
|
||||
use crate::util::common_commands::ffmpeg::ffmpeg_audio_replace_args::FfmpegAudioReplaceArgs;
|
||||
use crate::util::common_commands::ffmpeg::ffmpeg_audio_truncate_args::FfmpegAudioTruncateArgs;
|
||||
|
||||
const BUCKET_FILE_PREFIX: &str = "fakeyou_";
|
||||
const BUCKET_FILE_EXTENSION: &str = ".wav";
|
||||
@@ -132,7 +134,6 @@ pub async fn process_single_gpt_sovits_tts_job(
|
||||
reference_audio_path: reference_audio_path.as_deref(),
|
||||
reference_transcript_path: reference_transcript_path.as_deref(),
|
||||
reference_language: Some(DEFAULT_LANGUAGE),
|
||||
//output_audio_directory: &output_dir,
|
||||
output_file_path: &output_file_path,
|
||||
maybe_reference_free: None,
|
||||
maybe_temperature: None,
|
||||
@@ -160,27 +161,44 @@ pub async fn process_single_gpt_sovits_tts_job(
|
||||
|
||||
info!("Inference was successful.");
|
||||
|
||||
|
||||
// ==================== MAYBE TRUNCATE FILE ==================== //
|
||||
|
||||
//let command_exit_status = args
|
||||
// .comfy_deps
|
||||
// .ffmpeg_command_runner
|
||||
// .run_with_subprocess(RunAsSubprocessArgs {
|
||||
// args: Box::new(&FfmpegAudioReplaceArgs {
|
||||
// input_video_file: &args.videos.primary_video.comfy_output_video_path,
|
||||
// input_audio_file: &input_video_file,
|
||||
// output_video_file: &output_video_fs_path_restored,
|
||||
// }),
|
||||
// stderr: StreamRedirection::None,
|
||||
// stdout: StreamRedirection::None,
|
||||
// });
|
||||
// NB: This will be the final audio file we upload to the bucket
|
||||
let mut audio_for_upload_path = output_file_path.clone();
|
||||
|
||||
if let Some(truncate_seconds) = job_args.maybe_truncate_seconds {
|
||||
if truncate_seconds > 0 {
|
||||
let truncated_audio_output_path = output_dir.join("truncated.wav");
|
||||
|
||||
let command_exit_status = gpt_sovits_deps
|
||||
.ffmpeg_command_runner
|
||||
.run_with_subprocess(RunAsSubprocessArgs {
|
||||
args: Box::new(&FfmpegAudioTruncateArgs {
|
||||
input_audio_file: &output_file_path,
|
||||
output_audio_file: &truncated_audio_output_path,
|
||||
truncate_seconds: truncate_seconds as usize,
|
||||
}),
|
||||
stderr: StreamRedirection::Pipe,
|
||||
stdout: StreamRedirection::Pipe,
|
||||
});
|
||||
|
||||
if !command_exit_status.is_success() {
|
||||
warn!("Error truncating audio file. Exit status: {:?}", command_exit_status);
|
||||
}
|
||||
|
||||
if file_exists(&truncated_audio_output_path) {
|
||||
info!("Truncated audio file created successfully.");
|
||||
audio_for_upload_path = truncated_audio_output_path;
|
||||
} else {
|
||||
warn!("Truncated audio file does not exist: {:?}", &truncated_audio_output_path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ==================== DECODE AUDIO FILE ==================== //
|
||||
|
||||
let maybe_audio_info = decode_basic_audio_file_info(
|
||||
&output_file_path, Some(MIME_TYPE), Some("wav"))
|
||||
&audio_for_upload_path, Some(MIME_TYPE), Some("wav"))
|
||||
.map_err(|err| {
|
||||
warn!("Error decoding audio info: {:?}", err);
|
||||
err
|
||||
@@ -210,13 +228,13 @@ pub async fn process_single_gpt_sovits_tts_job(
|
||||
let result_bucket_object_pathbuf = result_bucket_location.to_full_object_pathbuf();
|
||||
|
||||
// Finished file path
|
||||
info!("Upload File Path: {:?}", &audio_for_upload_path);
|
||||
info!("Upload Bucket Path: {:?}", result_bucket_object_pathbuf);
|
||||
info!("Upload File Path: {:?}", &output_file_path);
|
||||
|
||||
job_dependencies.buckets.public_bucket_client
|
||||
.upload_filename_with_content_type(
|
||||
&result_bucket_object_pathbuf,
|
||||
&output_file_path,
|
||||
&audio_for_upload_path,
|
||||
&MIME_TYPE
|
||||
)
|
||||
.await
|
||||
@@ -226,11 +244,11 @@ pub async fn process_single_gpt_sovits_tts_job(
|
||||
|
||||
info!("Calculating sha256...");
|
||||
|
||||
let file_checksum = sha256_hash_file(&output_file_path).map_err(|err| {
|
||||
let file_checksum = sha256_hash_file(&audio_for_upload_path).map_err(|err| {
|
||||
ProcessSingleJobError::Other(anyhow!("Error hashing file: {:?}", err))
|
||||
})?;
|
||||
|
||||
let file_size_bytes = file_size(&output_file_path).map_err(|err|
|
||||
let file_size_bytes = file_size(&audio_for_upload_path).map_err(|err|
|
||||
ProcessSingleJobError::Other(err)
|
||||
)?;
|
||||
|
||||
|
||||
+2
-2
@@ -3,13 +3,13 @@ use std::path::Path;
|
||||
use filesys::path_to_string::path_to_string;
|
||||
use subprocess_common::command_runner::command_args::CommandArgs;
|
||||
|
||||
pub struct FfmpegAudioReplaceArgs<'a> {
|
||||
pub struct FfmpegAudioTruncateArgs<'a> {
|
||||
pub input_audio_file: &'a Path,
|
||||
pub output_audio_file: &'a Path,
|
||||
pub truncate_seconds: usize,
|
||||
}
|
||||
|
||||
impl CommandArgs for FfmpegAudioReplaceArgs<'_> {
|
||||
impl CommandArgs for FfmpegAudioTruncateArgs<'_> {
|
||||
|
||||
// eg. ffmpeg -i input-audio.aac -t 15 -c copy output.aac
|
||||
// time is in seconds
|
||||
|
||||
-15
@@ -11,21 +11,6 @@ use errors::AnyhowResult;
|
||||
use filesys::path_to_string::path_to_string;
|
||||
use subprocess_common::command_exit_status::CommandExitStatus;
|
||||
|
||||
// These environment vars are not copied over to the subprocess
|
||||
// TODO/FIXME(bt, 2023-05-28): This is horrific security!
|
||||
static IGNORED_ENVIRONMENT_VARS : Lazy<HashSet<String>> = Lazy::new(|| {
|
||||
let env_var_names= [
|
||||
"MYSQL_URL",
|
||||
"ACCESS_KEY",
|
||||
"SECRET_KEY",
|
||||
"NEWRELIC_API_KEY",
|
||||
];
|
||||
|
||||
env_var_names.iter()
|
||||
.map(|value| value.to_string())
|
||||
.collect::<HashSet<String>>()
|
||||
});
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct FfmpegLogoWatermarkCommand {
|
||||
/// A single executable script or a much larger bash command.
|
||||
|
||||
Reference in new issue
Block a user