mixvideo-v2/apps/desktop/src-tauri/src/business/services/model_dynamic_service.rs

244 lines
8.3 KiB
Rust

use anyhow::{anyhow, Result};
use crate::data::repositories::model_dynamic_repository::ModelDynamicRepository;
use crate::data::models::model_dynamic::{
ModelDynamic, GeneratedVideo, CreateModelDynamicRequest, UpdateModelDynamicRequest,
ModelDynamicStats, DynamicStatus, VideoGenerationStatus
};
use crate::business::errors::BusinessError;
/// 模特动态服务
/// 遵循 Tauri 开发规范的业务逻辑层设计原则
pub struct ModelDynamicService;
impl ModelDynamicService {
/// 创建模特动态
pub fn create_dynamic(
repository: &ModelDynamicRepository,
request: CreateModelDynamicRequest,
) -> Result<ModelDynamic> {
// 验证请求数据
if request.model_id.is_empty() {
return Err(BusinessError::InvalidInput("模特ID不能为空".to_string()).into());
}
if request.description.trim().is_empty() {
return Err(BusinessError::InvalidInput("动态描述不能为空".to_string()).into());
}
if request.prompt.trim().is_empty() {
return Err(BusinessError::InvalidInput("提示词不能为空".to_string()).into());
}
if request.source_image_path.trim().is_empty() {
return Err(BusinessError::InvalidInput("源图片路径不能为空".to_string()).into());
}
if request.video_count < 1 || request.video_count > 9 {
return Err(BusinessError::InvalidInput("视频个数必须在1-9之间".to_string()).into());
}
// 创建动态
let dynamic = repository.create(request)
.map_err(|e| anyhow!("创建模特动态失败: {}", e))?;
Ok(dynamic)
}
/// 获取模特动态详情
pub fn get_dynamic_by_id(
repository: &ModelDynamicRepository,
id: &str,
) -> Result<Option<ModelDynamic>> {
repository.get_by_id(id)
.map_err(|e| anyhow!("获取模特动态详情失败: {}", e))
}
/// 获取模特的所有动态
pub fn get_dynamics_by_model_id(
repository: &ModelDynamicRepository,
model_id: &str,
) -> Result<Vec<ModelDynamic>> {
repository.get_by_model_id(model_id)
.map_err(|e| anyhow!("获取模特动态列表失败: {}", e))
}
/// 更新模特动态
pub fn update_dynamic(
repository: &ModelDynamicRepository,
id: &str,
request: UpdateModelDynamicRequest,
) -> Result<ModelDynamic> {
// 检查动态是否存在
let dynamic = repository.get_by_id(id)?
.ok_or_else(|| BusinessError::NotFound(format!("动态不存在: {}", id)))?;
// 验证状态转换
if let Some(new_status) = &request.status {
Self::validate_status_transition(&dynamic.status, new_status)?;
}
// 更新动态
repository.update(id, request)
.map_err(|e| anyhow!("更新模特动态失败: {}", e))
}
/// 删除模特动态
pub fn delete_dynamic(
repository: &ModelDynamicRepository,
id: &str,
) -> Result<()> {
// 检查动态是否存在
let _dynamic = repository.get_by_id(id)?
.ok_or_else(|| BusinessError::NotFound(format!("动态不存在: {}", id)))?;
// 删除动态
repository.delete(id)
.map_err(|e| anyhow!("删除模特动态失败: {}", e))
}
/// 获取模特动态统计
pub fn get_stats_by_model_id(
repository: &ModelDynamicRepository,
model_id: &str,
) -> Result<ModelDynamicStats> {
repository.get_stats_by_model_id(model_id)
.map_err(|e| anyhow!("获取模特动态统计失败: {}", e))
}
/// 添加生成的视频
pub fn add_generated_video(
repository: &ModelDynamicRepository,
dynamic_id: &str,
video_path: String,
) -> Result<GeneratedVideo> {
// 检查动态是否存在
let mut dynamic = repository.get_by_id(dynamic_id)?
.ok_or_else(|| BusinessError::NotFound(format!("动态不存在: {}", dynamic_id)))?;
// 创建视频对象
let video = GeneratedVideo::new(dynamic_id.to_string(), video_path);
// 添加到动态
dynamic.add_generated_video(video.clone());
// 更新动态状态
if dynamic.status == DynamicStatus::Draft {
dynamic.update_status(DynamicStatus::Publishing);
}
// 更新动态
let request = UpdateModelDynamicRequest {
title: None,
description: None,
prompt: None,
status: Some(dynamic.status.clone()),
};
repository.update(dynamic_id, request)?;
Ok(video)
}
/// 更新视频生成进度
pub fn update_video_progress(
repository: &ModelDynamicRepository,
dynamic_id: &str,
video_id: &str,
progress: u32,
) -> Result<()> {
// 检查动态是否存在
let mut dynamic = repository.get_by_id(dynamic_id)?
.ok_or_else(|| BusinessError::NotFound(format!("动态不存在: {}", dynamic_id)))?;
// 查找视频
let video_index = dynamic.generated_videos.iter().position(|v| v.id == video_id)
.ok_or_else(|| BusinessError::NotFound(format!("视频不存在: {}", video_id)))?;
// 更新进度
dynamic.generated_videos[video_index].update_progress(progress);
// 检查是否所有视频都已完成
let all_completed = dynamic.generated_videos.iter()
.all(|v| v.status == VideoGenerationStatus::Completed || v.status == VideoGenerationStatus::Failed);
// 如果所有视频都已完成,更新动态状态为已发布
if all_completed && dynamic.status == DynamicStatus::Publishing {
dynamic.update_status(DynamicStatus::Published);
}
// 更新动态
let request = UpdateModelDynamicRequest {
title: None,
description: None,
prompt: None,
status: Some(dynamic.status.clone()),
};
repository.update(dynamic_id, request)?;
Ok(())
}
/// 标记视频生成失败
pub fn mark_video_as_failed(
repository: &ModelDynamicRepository,
dynamic_id: &str,
video_id: &str,
error_message: String,
) -> Result<()> {
// 检查动态是否存在
let mut dynamic = repository.get_by_id(dynamic_id)?
.ok_or_else(|| BusinessError::NotFound(format!("动态不存在: {}", dynamic_id)))?;
// 查找视频
let video_index = dynamic.generated_videos.iter().position(|v| v.id == video_id)
.ok_or_else(|| BusinessError::NotFound(format!("视频不存在: {}", video_id)))?;
// 标记为失败
dynamic.generated_videos[video_index].mark_as_failed(error_message);
// 检查是否所有视频都已完成
let all_completed = dynamic.generated_videos.iter()
.all(|v| v.status == VideoGenerationStatus::Completed || v.status == VideoGenerationStatus::Failed);
// 如果所有视频都已完成,更新动态状态为已发布
if all_completed && dynamic.status == DynamicStatus::Publishing {
dynamic.update_status(DynamicStatus::Published);
}
// 更新动态
let request = UpdateModelDynamicRequest {
title: None,
description: None,
prompt: None,
status: Some(dynamic.status.clone()),
};
repository.update(dynamic_id, request)?;
Ok(())
}
/// 验证状态转换
fn validate_status_transition(
current_status: &DynamicStatus,
new_status: &DynamicStatus,
) -> Result<()> {
match (current_status, new_status) {
// 允许的状态转换
(DynamicStatus::Draft, DynamicStatus::Publishing) => Ok(()),
(DynamicStatus::Publishing, DynamicStatus::Published) => Ok(()),
(DynamicStatus::Publishing, DynamicStatus::Failed) => Ok(()),
(DynamicStatus::Failed, DynamicStatus::Publishing) => Ok(()),
// 相同状态
(a, b) if a == b => Ok(()),
// 不允许的状态转换
_ => Err(BusinessError::InvalidState(format!(
"不允许的状态转换: {:?} -> {:?}",
current_status, new_status
)).into()),
}
}
}