mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-04 17:38:10 +00:00
document new endpoints
This commit is contained in:
1 parent
0bf9e7b5aa
commit
f49e49832b
4 files changed
+113
-95
No files matched your search
@@ -128,6 +128,9 @@ use crate::http_server::endpoints::weights::search_model_weights_handler::*;
|
||||
use crate::http_server::endpoints::weights::set_model_weight_cover_image_handler::*;
|
||||
use crate::http_server::endpoints::weights::update_weight_handler::*;
|
||||
use crate::http_server::endpoints::workflows::enqueue_video_style_transfer_handler::*;
|
||||
use crate::http_server::endpoints::workflows::enqueue::enqueue_live_portrait_workflow_handler::*;
|
||||
use crate::http_server::endpoints::workflows::enqueue::enqueue_studio_workflow_handler::*;
|
||||
use crate::http_server::endpoints::workflows::enqueue::enqueue_video_style_transfer_workflow_handler::*;
|
||||
use crate::http_server::web_utils::response_success_helpers::*;
|
||||
|
||||
#[derive(OpenApi)]
|
||||
@@ -212,6 +215,9 @@ use crate::http_server::web_utils::response_success_helpers::*;
|
||||
crate::http_server::endpoints::weights::set_model_weight_cover_image_handler::set_model_weight_cover_image_handler,
|
||||
crate::http_server::endpoints::weights::update_weight_handler::update_weight_handler,
|
||||
crate::http_server::endpoints::workflows::enqueue_video_style_transfer_handler::enqueue_video_style_transfer_handler,
|
||||
crate::http_server::endpoints::workflows::enqueue::enqueue_live_portrait_workflow_handler::enqueue_live_portrait_workflow_handler,
|
||||
crate::http_server::endpoints::workflows::enqueue::enqueue_studio_workflow_handler::enqueue_studio_workflow_handler,
|
||||
crate::http_server::endpoints::workflows::enqueue::enqueue_video_style_transfer_workflow_handler::enqueue_video_style_transfer_workflow_handler,
|
||||
),
|
||||
components(schemas(
|
||||
// Tokens
|
||||
@@ -349,12 +355,21 @@ use crate::http_server::web_utils::response_success_helpers::*;
|
||||
EnqueueFbxToGltfRequest,
|
||||
EnqueueFbxToGltfRequestError,
|
||||
EnqueueFbxToGltfRequestSuccessResponse,
|
||||
EnqueueLivePortraitWorkflowError,
|
||||
EnqueueLivePortraitWorkflowRequest,
|
||||
EnqueueLivePortraitWorkflowSuccessResponse,
|
||||
EnqueueStudioWorkflowError,
|
||||
EnqueueStudioWorkflowRequest,
|
||||
EnqueueStudioWorkflowSuccessResponse,
|
||||
EnqueueTTSRequest,
|
||||
EnqueueTTSRequestError,
|
||||
EnqueueTTSRequestSuccessResponse,
|
||||
EnqueueVideoStyleTransferError,
|
||||
EnqueueVideoStyleTransferRequest,
|
||||
EnqueueVideoStyleTransferSuccessResponse,
|
||||
EnqueueVideoStyleTransferWorkflowError,
|
||||
EnqueueVideoStyleTransferWorkflowRequest,
|
||||
EnqueueVideoStyleTransferWorkflowSuccessResponse,
|
||||
EnqueueVoiceConversionInferenceError,
|
||||
EnqueueVoiceConversionInferenceRequest,
|
||||
EnqueueVoiceConversionInferenceSuccessResponse,
|
||||
|
||||
+30
-29
@@ -38,7 +38,7 @@ use crate::http_server::web_utils::response_error_helpers::to_simple_json_error;
|
||||
use crate::state::server_state::ServerState;
|
||||
|
||||
#[derive(Deserialize, ToSchema)]
|
||||
pub struct EnqueueLivePortraitRequest {
|
||||
pub struct EnqueueLivePortraitWorkflowRequest {
|
||||
/// Entropy for request de-duplication (required)
|
||||
uuid_idempotency_token: String,
|
||||
|
||||
@@ -59,35 +59,35 @@ pub struct EnqueueLivePortraitRequest {
|
||||
}
|
||||
|
||||
#[derive(Serialize, ToSchema)]
|
||||
pub struct EnqueueLivePortraitSuccessResponse {
|
||||
pub struct EnqueueLivePortraitWorkflowSuccessResponse {
|
||||
pub success: bool,
|
||||
pub inference_job_token: InferenceJobToken,
|
||||
}
|
||||
|
||||
#[derive(Debug, ToSchema)]
|
||||
pub enum EnqueueLivePortraitError {
|
||||
pub enum EnqueueLivePortraitWorkflowError {
|
||||
BadInput(String),
|
||||
NotAuthorized,
|
||||
ServerError,
|
||||
RateLimited,
|
||||
}
|
||||
|
||||
impl ResponseError for EnqueueLivePortraitError {
|
||||
impl ResponseError for EnqueueLivePortraitWorkflowError {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match *self {
|
||||
EnqueueLivePortraitError::BadInput(_) => StatusCode::BAD_REQUEST,
|
||||
EnqueueLivePortraitError::NotAuthorized => StatusCode::UNAUTHORIZED,
|
||||
EnqueueLivePortraitError::ServerError => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
EnqueueLivePortraitError::RateLimited => StatusCode::TOO_MANY_REQUESTS,
|
||||
EnqueueLivePortraitWorkflowError::BadInput(_) => StatusCode::BAD_REQUEST,
|
||||
EnqueueLivePortraitWorkflowError::NotAuthorized => StatusCode::UNAUTHORIZED,
|
||||
EnqueueLivePortraitWorkflowError::ServerError => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
EnqueueLivePortraitWorkflowError::RateLimited => StatusCode::TOO_MANY_REQUESTS,
|
||||
}
|
||||
}
|
||||
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
let error_reason = match self {
|
||||
EnqueueLivePortraitError::BadInput(reason) => reason.to_string(),
|
||||
EnqueueLivePortraitError::NotAuthorized => "unauthorized".to_string(),
|
||||
EnqueueLivePortraitError::ServerError => "server error".to_string(),
|
||||
EnqueueLivePortraitError::RateLimited => "rate limited".to_string(),
|
||||
EnqueueLivePortraitWorkflowError::BadInput(reason) => reason.to_string(),
|
||||
EnqueueLivePortraitWorkflowError::NotAuthorized => "unauthorized".to_string(),
|
||||
EnqueueLivePortraitWorkflowError::ServerError => "server error".to_string(),
|
||||
EnqueueLivePortraitWorkflowError::RateLimited => "rate limited".to_string(),
|
||||
};
|
||||
|
||||
to_simple_json_error(&error_reason, self.status_code())
|
||||
@@ -95,29 +95,30 @@ impl ResponseError for EnqueueLivePortraitError {
|
||||
}
|
||||
|
||||
// NB: Not using derive_more::Display since Clion doesn't understand it.
|
||||
impl std::fmt::Display for EnqueueLivePortraitError {
|
||||
impl std::fmt::Display for EnqueueLivePortraitWorkflowError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Enqueue live portrait video workflows.
|
||||
#[utoipa::path(
|
||||
post,
|
||||
tag = "Workflows",
|
||||
path = "/v1/workflows/enqueue_live_portrait",
|
||||
responses(
|
||||
(status = 200, description = "Success", body = EnqueueLivePortraitSuccessResponse),
|
||||
(status = 400, description = "Bad input", body = EnqueueLivePortraitError),
|
||||
(status = 401, description = "Not authorized", body = EnqueueLivePortraitError),
|
||||
(status = 429, description = "Rate limited", body = EnqueueLivePortraitError),
|
||||
(status = 500, description = "Server error", body = EnqueueLivePortraitError)
|
||||
(status = 200, description = "Success", body = EnqueueLivePortraitWorkflowSuccessResponse),
|
||||
(status = 400, description = "Bad input", body = EnqueueLivePortraitWorkflowError),
|
||||
(status = 401, description = "Not authorized", body = EnqueueLivePortraitWorkflowError),
|
||||
(status = 429, description = "Rate limited", body = EnqueueLivePortraitWorkflowError),
|
||||
(status = 500, description = "Server error", body = EnqueueLivePortraitWorkflowError)
|
||||
),
|
||||
params(("request" = EnqueueLivePortraitRequest, description = "Payload for request"))
|
||||
params(("request" = EnqueueLivePortraitWorkflowRequest, description = "Payload for request"))
|
||||
)]
|
||||
pub async fn enqueue_live_portrait_workflow_handler(
|
||||
http_request: HttpRequest,
|
||||
request: web::Json<EnqueueLivePortraitRequest>,
|
||||
server_state: web::Data<Arc<ServerState>>) -> Result<Json<EnqueueLivePortraitSuccessResponse>, EnqueueLivePortraitError>
|
||||
request: Json<EnqueueLivePortraitWorkflowRequest>,
|
||||
server_state: web::Data<Arc<ServerState>>) -> Result<Json<EnqueueLivePortraitWorkflowSuccessResponse>, EnqueueLivePortraitWorkflowError>
|
||||
{
|
||||
// ==================== DB ==================== //
|
||||
|
||||
@@ -126,7 +127,7 @@ pub async fn enqueue_live_portrait_workflow_handler(
|
||||
.await
|
||||
.map_err(|err| {
|
||||
warn!("MySql pool error: {:?}", err);
|
||||
EnqueueLivePortraitError::ServerError
|
||||
EnqueueLivePortraitWorkflowError::ServerError
|
||||
})?;
|
||||
|
||||
// ==================== USER SESSION ==================== //
|
||||
@@ -140,8 +141,8 @@ pub async fn enqueue_live_portrait_workflow_handler(
|
||||
&mut mysql_connection)
|
||||
.await
|
||||
.map_err(|err| match err {
|
||||
RequireUserSessionError::ServerError => EnqueueLivePortraitError::ServerError,
|
||||
RequireUserSessionError::NotAuthorized => EnqueueLivePortraitError::NotAuthorized,
|
||||
RequireUserSessionError::ServerError => EnqueueLivePortraitWorkflowError::ServerError,
|
||||
RequireUserSessionError::NotAuthorized => EnqueueLivePortraitWorkflowError::NotAuthorized,
|
||||
})?;
|
||||
|
||||
// ==================== PAID PLAN + PRIORITY ==================== //
|
||||
@@ -163,20 +164,20 @@ pub async fn enqueue_live_portrait_workflow_handler(
|
||||
// ==================== RATE LIMIT ==================== //
|
||||
|
||||
if let Err(_err) = server_state.redis_rate_limiters.logged_in.rate_limit_request(&http_request) {
|
||||
return Err(EnqueueLivePortraitError::RateLimited);
|
||||
return Err(EnqueueLivePortraitWorkflowError::RateLimited);
|
||||
}
|
||||
|
||||
// ==================== HANDLE IDEMPOTENCY ==================== //
|
||||
|
||||
if let Err(reason) = validate_idempotency_token_format(&request.uuid_idempotency_token) {
|
||||
return Err(EnqueueLivePortraitError::BadInput(reason));
|
||||
return Err(EnqueueLivePortraitWorkflowError::BadInput(reason));
|
||||
}
|
||||
|
||||
insert_idempotency_token(&request.uuid_idempotency_token, &mut *mysql_connection)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
error!("Error inserting idempotency token: {:?}", err);
|
||||
EnqueueLivePortraitError::BadInput("invalid idempotency token".to_string())
|
||||
EnqueueLivePortraitWorkflowError::BadInput("invalid idempotency token".to_string())
|
||||
})?;
|
||||
|
||||
// ==================== LOOK UP MODEL INFO ==================== //
|
||||
@@ -277,11 +278,11 @@ pub async fn enqueue_live_portrait_workflow_handler(
|
||||
Ok((job_token, _id)) => job_token,
|
||||
Err(err) => {
|
||||
warn!("New generic inference job creation DB error: {:?}", err);
|
||||
return Err(EnqueueLivePortraitError::ServerError);
|
||||
return Err(EnqueueLivePortraitWorkflowError::ServerError);
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Json(EnqueueLivePortraitSuccessResponse {
|
||||
Ok(Json(EnqueueLivePortraitWorkflowSuccessResponse {
|
||||
success: true,
|
||||
inference_job_token: job_token,
|
||||
}))
|
||||
|
||||
+34
-33
@@ -57,7 +57,7 @@ const MAXIMUM_STRENGTH : f32 = 1.0;
|
||||
const DEFAULT_STRENGTH : f32 = 1.0;
|
||||
|
||||
#[derive(Deserialize, ToSchema)]
|
||||
pub struct EnqueueVideoStyleTransferRequest {
|
||||
pub struct EnqueueStudioWorkflowRequest {
|
||||
/// Entropy for request de-duplication (required)
|
||||
uuid_idempotency_token: String,
|
||||
|
||||
@@ -162,35 +162,35 @@ pub struct EnqueueVideoStyleTransferRequest {
|
||||
}
|
||||
|
||||
#[derive(Serialize, ToSchema)]
|
||||
pub struct EnqueueVideoStyleTransferSuccessResponse {
|
||||
pub struct EnqueueStudioWorkflowSuccessResponse {
|
||||
pub success: bool,
|
||||
pub inference_job_token: InferenceJobToken,
|
||||
}
|
||||
|
||||
#[derive(Debug, ToSchema)]
|
||||
pub enum EnqueueVideoStyleTransferError {
|
||||
pub enum EnqueueStudioWorkflowError {
|
||||
BadInput(String),
|
||||
NotAuthorized,
|
||||
ServerError,
|
||||
RateLimited,
|
||||
}
|
||||
|
||||
impl ResponseError for EnqueueVideoStyleTransferError {
|
||||
impl ResponseError for EnqueueStudioWorkflowError {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match *self {
|
||||
EnqueueVideoStyleTransferError::BadInput(_) => StatusCode::BAD_REQUEST,
|
||||
EnqueueVideoStyleTransferError::NotAuthorized => StatusCode::UNAUTHORIZED,
|
||||
EnqueueVideoStyleTransferError::ServerError => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
EnqueueVideoStyleTransferError::RateLimited => StatusCode::TOO_MANY_REQUESTS,
|
||||
EnqueueStudioWorkflowError::BadInput(_) => StatusCode::BAD_REQUEST,
|
||||
EnqueueStudioWorkflowError::NotAuthorized => StatusCode::UNAUTHORIZED,
|
||||
EnqueueStudioWorkflowError::ServerError => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
EnqueueStudioWorkflowError::RateLimited => StatusCode::TOO_MANY_REQUESTS,
|
||||
}
|
||||
}
|
||||
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
let error_reason = match self {
|
||||
EnqueueVideoStyleTransferError::BadInput(reason) => reason.to_string(),
|
||||
EnqueueVideoStyleTransferError::NotAuthorized => "unauthorized".to_string(),
|
||||
EnqueueVideoStyleTransferError::ServerError => "server error".to_string(),
|
||||
EnqueueVideoStyleTransferError::RateLimited => "rate limited".to_string(),
|
||||
EnqueueStudioWorkflowError::BadInput(reason) => reason.to_string(),
|
||||
EnqueueStudioWorkflowError::NotAuthorized => "unauthorized".to_string(),
|
||||
EnqueueStudioWorkflowError::ServerError => "server error".to_string(),
|
||||
EnqueueStudioWorkflowError::RateLimited => "rate limited".to_string(),
|
||||
};
|
||||
|
||||
to_simple_json_error(&error_reason, self.status_code())
|
||||
@@ -198,36 +198,37 @@ impl ResponseError for EnqueueVideoStyleTransferError {
|
||||
}
|
||||
|
||||
// NB: Not using derive_more::Display since Clion doesn't understand it.
|
||||
impl std::fmt::Display for EnqueueVideoStyleTransferError {
|
||||
impl std::fmt::Display for EnqueueStudioWorkflowError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Enqueue Storyteller Studio video workflows.
|
||||
#[utoipa::path(
|
||||
post,
|
||||
tag = "Workflows",
|
||||
path = "/v1/workflows/enqueue_studio",
|
||||
responses(
|
||||
(status = 200, description = "Success", body = EnqueueVideoStyleTransferSuccessResponse),
|
||||
(status = 400, description = "Bad input", body = EnqueueVideoStyleTransferError),
|
||||
(status = 401, description = "Not authorized", body = EnqueueVideoStyleTransferError),
|
||||
(status = 429, description = "Rate limited", body = EnqueueVideoStyleTransferError),
|
||||
(status = 500, description = "Server error", body = EnqueueVideoStyleTransferError)
|
||||
(status = 200, description = "Success", body = EnqueueStudioWorkflowSuccessResponse),
|
||||
(status = 400, description = "Bad input", body = EnqueueStudioWorkflowError),
|
||||
(status = 401, description = "Not authorized", body = EnqueueStudioWorkflowError),
|
||||
(status = 429, description = "Rate limited", body = EnqueueStudioWorkflowError),
|
||||
(status = 500, description = "Server error", body = EnqueueStudioWorkflowError)
|
||||
),
|
||||
params(("request" = EnqueueVideoStyleTransferRequest, description = "Payload for request"))
|
||||
params(("request" = EnqueueStudioWorkflowRequest, description = "Payload for request"))
|
||||
)]
|
||||
pub async fn enqueue_studio_workflow_handler(
|
||||
http_request: HttpRequest,
|
||||
request: web::Json<EnqueueVideoStyleTransferRequest>,
|
||||
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, EnqueueVideoStyleTransferError>
|
||||
request: web::Json<EnqueueStudioWorkflowRequest>,
|
||||
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, EnqueueStudioWorkflowError>
|
||||
{
|
||||
// ==================== VALIDATION ==================== //
|
||||
|
||||
match request.frame_skip {
|
||||
None | Some(1) | Some(2) => {} // Allowed
|
||||
_ => {
|
||||
return Err(EnqueueVideoStyleTransferError::BadInput("Invalid frame skip value".to_string()));
|
||||
return Err(EnqueueStudioWorkflowError::BadInput("Invalid frame skip value".to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,7 +239,7 @@ pub async fn enqueue_studio_workflow_handler(
|
||||
.await
|
||||
.map_err(|err| {
|
||||
warn!("MySql pool error: {:?}", err);
|
||||
EnqueueVideoStyleTransferError::ServerError
|
||||
EnqueueStudioWorkflowError::ServerError
|
||||
})?;
|
||||
|
||||
let maybe_avt_token = server_state.avt_cookie_manager
|
||||
@@ -252,7 +253,7 @@ pub async fn enqueue_studio_workflow_handler(
|
||||
.await
|
||||
.map_err(|e| {
|
||||
warn!("Session checker error: {:?}", e);
|
||||
EnqueueVideoStyleTransferError::ServerError
|
||||
EnqueueStudioWorkflowError::ServerError
|
||||
})?;
|
||||
|
||||
let maybe_user_token = maybe_user_session
|
||||
@@ -263,7 +264,7 @@ pub async fn enqueue_studio_workflow_handler(
|
||||
|
||||
if !allowed_video_style_transfer_access(maybe_user_session.as_ref(), &server_state.flags) {
|
||||
warn!("Video style transfer access is not permitted for user");
|
||||
return Err(EnqueueVideoStyleTransferError::NotAuthorized);
|
||||
return Err(EnqueueStudioWorkflowError::NotAuthorized);
|
||||
}
|
||||
|
||||
// ==================== PAID PLAN + PRIORITY ==================== //
|
||||
@@ -293,27 +294,27 @@ pub async fn enqueue_studio_workflow_handler(
|
||||
None => &server_state.redis_rate_limiters.logged_out,
|
||||
Some(ref user) => {
|
||||
if user.role.is_banned {
|
||||
return Err(EnqueueVideoStyleTransferError::NotAuthorized);
|
||||
return Err(EnqueueStudioWorkflowError::NotAuthorized);
|
||||
}
|
||||
&server_state.redis_rate_limiters.logged_in
|
||||
},
|
||||
};
|
||||
|
||||
if let Err(_err) = rate_limiter.rate_limit_request(&http_request) {
|
||||
return Err(EnqueueVideoStyleTransferError::RateLimited);
|
||||
return Err(EnqueueStudioWorkflowError::RateLimited);
|
||||
}
|
||||
|
||||
// ==================== HANDLE IDEMPOTENCY ==================== //
|
||||
|
||||
if let Err(reason) = validate_idempotency_token_format(&request.uuid_idempotency_token) {
|
||||
return Err(EnqueueVideoStyleTransferError::BadInput(reason));
|
||||
return Err(EnqueueStudioWorkflowError::BadInput(reason));
|
||||
}
|
||||
|
||||
insert_idempotency_token(&request.uuid_idempotency_token, &mut *mysql_connection)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
error!("Error inserting idempotency token: {:?}", err);
|
||||
EnqueueVideoStyleTransferError::BadInput("invalid idempotency token".to_string())
|
||||
EnqueueStudioWorkflowError::BadInput("invalid idempotency token".to_string())
|
||||
})?;
|
||||
|
||||
// ==================== LOOK UP MODEL INFO ==================== //
|
||||
@@ -351,7 +352,7 @@ pub async fn enqueue_studio_workflow_handler(
|
||||
let maybe_strength = request.use_strength
|
||||
.map(|strength| {
|
||||
if strength < MINIMUM_STRENGTH || strength > MAXIMUM_STRENGTH {
|
||||
Err(EnqueueVideoStyleTransferError::BadInput("Strength must be between 0.0 and 1.0".to_string()))
|
||||
Err(EnqueueStudioWorkflowError::BadInput("Strength must be between 0.0 and 1.0".to_string()))
|
||||
} else {
|
||||
Ok(strength)
|
||||
}
|
||||
@@ -470,17 +471,17 @@ pub async fn enqueue_studio_workflow_handler(
|
||||
Ok((job_token, _id)) => job_token,
|
||||
Err(err) => {
|
||||
warn!("New generic inference job creation DB error: {:?}", err);
|
||||
return Err(EnqueueVideoStyleTransferError::ServerError);
|
||||
return Err(EnqueueStudioWorkflowError::ServerError);
|
||||
}
|
||||
};
|
||||
|
||||
let response: EnqueueVideoStyleTransferSuccessResponse = EnqueueVideoStyleTransferSuccessResponse {
|
||||
let response: EnqueueStudioWorkflowSuccessResponse = EnqueueStudioWorkflowSuccessResponse {
|
||||
success: true,
|
||||
inference_job_token: job_token,
|
||||
};
|
||||
|
||||
let body = serde_json::to_string(&response)
|
||||
.map_err(|_e| EnqueueVideoStyleTransferError::ServerError)?;
|
||||
.map_err(|_e| EnqueueStudioWorkflowError::ServerError)?;
|
||||
|
||||
Ok(HttpResponse::Ok()
|
||||
.content_type("application/json")
|
||||
|
||||
+34
-33
@@ -57,7 +57,7 @@ const MAXIMUM_STRENGTH : f32 = 1.0;
|
||||
const DEFAULT_STRENGTH : f32 = 1.0;
|
||||
|
||||
#[derive(Deserialize, ToSchema)]
|
||||
pub struct EnqueueVideoStyleTransferRequest {
|
||||
pub struct EnqueueVideoStyleTransferWorkflowRequest {
|
||||
/// Entropy for request de-duplication (required)
|
||||
uuid_idempotency_token: String,
|
||||
|
||||
@@ -162,35 +162,35 @@ pub struct EnqueueVideoStyleTransferRequest {
|
||||
}
|
||||
|
||||
#[derive(Serialize, ToSchema)]
|
||||
pub struct EnqueueVideoStyleTransferSuccessResponse {
|
||||
pub struct EnqueueVideoStyleTransferWorkflowSuccessResponse {
|
||||
pub success: bool,
|
||||
pub inference_job_token: InferenceJobToken,
|
||||
}
|
||||
|
||||
#[derive(Debug, ToSchema)]
|
||||
pub enum EnqueueVideoStyleTransferError {
|
||||
pub enum EnqueueVideoStyleTransferWorkflowError {
|
||||
BadInput(String),
|
||||
NotAuthorized,
|
||||
ServerError,
|
||||
RateLimited,
|
||||
}
|
||||
|
||||
impl ResponseError for EnqueueVideoStyleTransferError {
|
||||
impl ResponseError for EnqueueVideoStyleTransferWorkflowError {
|
||||
fn status_code(&self) -> StatusCode {
|
||||
match *self {
|
||||
EnqueueVideoStyleTransferError::BadInput(_) => StatusCode::BAD_REQUEST,
|
||||
EnqueueVideoStyleTransferError::NotAuthorized => StatusCode::UNAUTHORIZED,
|
||||
EnqueueVideoStyleTransferError::ServerError => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
EnqueueVideoStyleTransferError::RateLimited => StatusCode::TOO_MANY_REQUESTS,
|
||||
EnqueueVideoStyleTransferWorkflowError::BadInput(_) => StatusCode::BAD_REQUEST,
|
||||
EnqueueVideoStyleTransferWorkflowError::NotAuthorized => StatusCode::UNAUTHORIZED,
|
||||
EnqueueVideoStyleTransferWorkflowError::ServerError => StatusCode::INTERNAL_SERVER_ERROR,
|
||||
EnqueueVideoStyleTransferWorkflowError::RateLimited => StatusCode::TOO_MANY_REQUESTS,
|
||||
}
|
||||
}
|
||||
|
||||
fn error_response(&self) -> HttpResponse {
|
||||
let error_reason = match self {
|
||||
EnqueueVideoStyleTransferError::BadInput(reason) => reason.to_string(),
|
||||
EnqueueVideoStyleTransferError::NotAuthorized => "unauthorized".to_string(),
|
||||
EnqueueVideoStyleTransferError::ServerError => "server error".to_string(),
|
||||
EnqueueVideoStyleTransferError::RateLimited => "rate limited".to_string(),
|
||||
EnqueueVideoStyleTransferWorkflowError::BadInput(reason) => reason.to_string(),
|
||||
EnqueueVideoStyleTransferWorkflowError::NotAuthorized => "unauthorized".to_string(),
|
||||
EnqueueVideoStyleTransferWorkflowError::ServerError => "server error".to_string(),
|
||||
EnqueueVideoStyleTransferWorkflowError::RateLimited => "rate limited".to_string(),
|
||||
};
|
||||
|
||||
to_simple_json_error(&error_reason, self.status_code())
|
||||
@@ -198,36 +198,37 @@ impl ResponseError for EnqueueVideoStyleTransferError {
|
||||
}
|
||||
|
||||
// NB: Not using derive_more::Display since Clion doesn't understand it.
|
||||
impl std::fmt::Display for EnqueueVideoStyleTransferError {
|
||||
impl std::fmt::Display for EnqueueVideoStyleTransferWorkflowError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Enqueue video style transfer video workflows.
|
||||
#[utoipa::path(
|
||||
post,
|
||||
tag = "Workflows",
|
||||
path = "/v1/workflows/enqueue_vst",
|
||||
responses(
|
||||
(status = 200, description = "Success", body = EnqueueVideoStyleTransferSuccessResponse),
|
||||
(status = 400, description = "Bad input", body = EnqueueVideoStyleTransferError),
|
||||
(status = 401, description = "Not authorized", body = EnqueueVideoStyleTransferError),
|
||||
(status = 429, description = "Rate limited", body = EnqueueVideoStyleTransferError),
|
||||
(status = 500, description = "Server error", body = EnqueueVideoStyleTransferError)
|
||||
(status = 200, description = "Success", body = EnqueueVideoStyleTransferWorkflowSuccessResponse),
|
||||
(status = 400, description = "Bad input", body = EnqueueVideoStyleTransferWorkflowError),
|
||||
(status = 401, description = "Not authorized", body = EnqueueVideoStyleTransferWorkflowError),
|
||||
(status = 429, description = "Rate limited", body = EnqueueVideoStyleTransferWorkflowError),
|
||||
(status = 500, description = "Server error", body = EnqueueVideoStyleTransferWorkflowError)
|
||||
),
|
||||
params(("request" = EnqueueVideoStyleTransferRequest, description = "Payload for request"))
|
||||
params(("request" = EnqueueVideoStyleTransferWorkflowRequest, description = "Payload for request"))
|
||||
)]
|
||||
pub async fn enqueue_video_style_transfer_workflow_handler(
|
||||
http_request: HttpRequest,
|
||||
request: web::Json<EnqueueVideoStyleTransferRequest>,
|
||||
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, EnqueueVideoStyleTransferError>
|
||||
request: web::Json<EnqueueVideoStyleTransferWorkflowRequest>,
|
||||
server_state: web::Data<Arc<ServerState>>) -> Result<HttpResponse, EnqueueVideoStyleTransferWorkflowError>
|
||||
{
|
||||
// ==================== VALIDATION ==================== //
|
||||
|
||||
match request.frame_skip {
|
||||
None | Some(1) | Some(2) => {} // Allowed
|
||||
_ => {
|
||||
return Err(EnqueueVideoStyleTransferError::BadInput("Invalid frame skip value".to_string()));
|
||||
return Err(EnqueueVideoStyleTransferWorkflowError::BadInput("Invalid frame skip value".to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,7 +239,7 @@ pub async fn enqueue_video_style_transfer_workflow_handler(
|
||||
.await
|
||||
.map_err(|err| {
|
||||
warn!("MySql pool error: {:?}", err);
|
||||
EnqueueVideoStyleTransferError::ServerError
|
||||
EnqueueVideoStyleTransferWorkflowError::ServerError
|
||||
})?;
|
||||
|
||||
let maybe_avt_token = server_state.avt_cookie_manager
|
||||
@@ -252,7 +253,7 @@ pub async fn enqueue_video_style_transfer_workflow_handler(
|
||||
.await
|
||||
.map_err(|e| {
|
||||
warn!("Session checker error: {:?}", e);
|
||||
EnqueueVideoStyleTransferError::ServerError
|
||||
EnqueueVideoStyleTransferWorkflowError::ServerError
|
||||
})?;
|
||||
|
||||
let maybe_user_token = maybe_user_session
|
||||
@@ -263,7 +264,7 @@ pub async fn enqueue_video_style_transfer_workflow_handler(
|
||||
|
||||
if !allowed_video_style_transfer_access(maybe_user_session.as_ref(), &server_state.flags) {
|
||||
warn!("Video style transfer access is not permitted for user");
|
||||
return Err(EnqueueVideoStyleTransferError::NotAuthorized);
|
||||
return Err(EnqueueVideoStyleTransferWorkflowError::NotAuthorized);
|
||||
}
|
||||
|
||||
// ==================== PAID PLAN + PRIORITY ==================== //
|
||||
@@ -293,27 +294,27 @@ pub async fn enqueue_video_style_transfer_workflow_handler(
|
||||
None => &server_state.redis_rate_limiters.logged_out,
|
||||
Some(ref user) => {
|
||||
if user.role.is_banned {
|
||||
return Err(EnqueueVideoStyleTransferError::NotAuthorized);
|
||||
return Err(EnqueueVideoStyleTransferWorkflowError::NotAuthorized);
|
||||
}
|
||||
&server_state.redis_rate_limiters.logged_in
|
||||
},
|
||||
};
|
||||
|
||||
if let Err(_err) = rate_limiter.rate_limit_request(&http_request) {
|
||||
return Err(EnqueueVideoStyleTransferError::RateLimited);
|
||||
return Err(EnqueueVideoStyleTransferWorkflowError::RateLimited);
|
||||
}
|
||||
|
||||
// ==================== HANDLE IDEMPOTENCY ==================== //
|
||||
|
||||
if let Err(reason) = validate_idempotency_token_format(&request.uuid_idempotency_token) {
|
||||
return Err(EnqueueVideoStyleTransferError::BadInput(reason));
|
||||
return Err(EnqueueVideoStyleTransferWorkflowError::BadInput(reason));
|
||||
}
|
||||
|
||||
insert_idempotency_token(&request.uuid_idempotency_token, &mut *mysql_connection)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
error!("Error inserting idempotency token: {:?}", err);
|
||||
EnqueueVideoStyleTransferError::BadInput("invalid idempotency token".to_string())
|
||||
EnqueueVideoStyleTransferWorkflowError::BadInput("invalid idempotency token".to_string())
|
||||
})?;
|
||||
|
||||
// ==================== LOOK UP MODEL INFO ==================== //
|
||||
@@ -351,7 +352,7 @@ pub async fn enqueue_video_style_transfer_workflow_handler(
|
||||
let maybe_strength = request.use_strength
|
||||
.map(|strength| {
|
||||
if strength < MINIMUM_STRENGTH || strength > MAXIMUM_STRENGTH {
|
||||
Err(EnqueueVideoStyleTransferError::BadInput("Strength must be between 0.0 and 1.0".to_string()))
|
||||
Err(EnqueueVideoStyleTransferWorkflowError::BadInput("Strength must be between 0.0 and 1.0".to_string()))
|
||||
} else {
|
||||
Ok(strength)
|
||||
}
|
||||
@@ -470,17 +471,17 @@ pub async fn enqueue_video_style_transfer_workflow_handler(
|
||||
Ok((job_token, _id)) => job_token,
|
||||
Err(err) => {
|
||||
warn!("New generic inference job creation DB error: {:?}", err);
|
||||
return Err(EnqueueVideoStyleTransferError::ServerError);
|
||||
return Err(EnqueueVideoStyleTransferWorkflowError::ServerError);
|
||||
}
|
||||
};
|
||||
|
||||
let response: EnqueueVideoStyleTransferSuccessResponse = EnqueueVideoStyleTransferSuccessResponse {
|
||||
let response: EnqueueVideoStyleTransferWorkflowSuccessResponse = EnqueueVideoStyleTransferWorkflowSuccessResponse {
|
||||
success: true,
|
||||
inference_job_token: job_token,
|
||||
};
|
||||
|
||||
let body = serde_json::to_string(&response)
|
||||
.map_err(|_e| EnqueueVideoStyleTransferError::ServerError)?;
|
||||
.map_err(|_e| EnqueueVideoStyleTransferWorkflowError::ServerError)?;
|
||||
|
||||
Ok(HttpResponse::Ok()
|
||||
.content_type("application/json")
|
||||
|
||||
Reference in new issue
Block a user