mixvideo-v2/apps/desktop/src-tauri/src/presentation/commands/outfit_image_commands.rs

221 lines
7.4 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

use tauri::State;
use crate::app_state::AppState;
use crate::data::models::outfit_image::{
OutfitImageRecord, OutfitImageGenerationRequest, OutfitImageGenerationResponse,
OutfitImageStats, ProductImage, OutfitImage
};
use crate::data::repositories::outfit_image_repository::OutfitImageRepository;
use crate::data::repositories::model_repository::ModelRepository;
use crate::data::models::model::PhotoType;
/// 模特个人看板统计信息
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct ModelDashboardStats {
pub model_id: String,
pub model_name: String,
pub total_photos: u32,
pub portrait_photos: u32,
pub work_photos: u32,
pub outfit_stats: OutfitImageStats,
pub recent_generations: u32,
pub success_rate: f32,
pub favorite_count: u32,
pub total_generation_time_ms: u64,
pub average_generation_time_ms: u64,
}
/// 获取模特个人看板统计信息
#[tauri::command]
pub async fn get_model_dashboard_stats(
state: State<'_, AppState>,
model_id: String,
) -> Result<ModelDashboardStats, String> {
println!("📊 获取模特个人看板统计信息: {}", model_id);
// 获取数据库连接
let database = state.get_database();
let outfit_repo = OutfitImageRepository::new(database.clone());
let model_repo = ModelRepository::new(database.clone());
// 获取模特基本信息
let model = model_repo.get_by_id(&model_id)
.map_err(|e| format!("获取模特信息失败: {}", e))?
.ok_or_else(|| "模特不存在".to_string())?;
// 获取穿搭图片统计
let outfit_stats = outfit_repo.get_stats_by_model_id(&model_id)
.map_err(|e| format!("获取穿搭图片统计失败: {}", e))?;
// 计算照片统计
let total_photos = model.photos.len() as u32;
let portrait_photos = model.photos.iter()
.filter(|photo| matches!(photo.photo_type, PhotoType::Portrait))
.count() as u32;
let work_photos = model.photos.iter()
.filter(|photo| matches!(photo.photo_type, PhotoType::Commercial | PhotoType::Artistic))
.count() as u32;
// 计算成功率
let success_rate = if outfit_stats.total_records > 0 {
outfit_stats.completed_records as f32 / outfit_stats.total_records as f32
} else {
0.0
};
// 获取最近30天的生成记录简化实现实际应该查询数据库
let recent_generations = outfit_stats.total_records; // TODO: 实现真正的30天统计
// 计算总生成时间和平均生成时间(简化实现)
let total_generation_time_ms = outfit_stats.completed_records as u64 * 5000; // 假设平均5秒
let average_generation_time_ms = if outfit_stats.completed_records > 0 {
total_generation_time_ms / outfit_stats.completed_records as u64
} else {
0
};
let dashboard_stats = ModelDashboardStats {
model_id: model_id.clone(),
model_name: model.name.clone(),
total_photos,
portrait_photos,
work_photos,
outfit_stats: outfit_stats.clone(),
recent_generations,
success_rate,
favorite_count: outfit_stats.favorite_images,
total_generation_time_ms,
average_generation_time_ms,
};
println!("✅ 模特个人看板统计信息获取成功");
Ok(dashboard_stats)
}
/// 获取模特的穿搭图片生成记录列表
#[tauri::command]
pub async fn get_outfit_image_records(
state: State<'_, AppState>,
model_id: String,
) -> Result<Vec<OutfitImageRecord>, String> {
println!("📋 获取模特穿搭图片生成记录: {}", model_id);
let database = state.get_database();
let outfit_repo = OutfitImageRepository::new(database);
let records = outfit_repo.get_records_by_model_id(&model_id)
.map_err(|e| format!("获取穿搭图片记录失败: {}", e))?;
println!("✅ 获取到 {} 条穿搭图片记录", records.len());
Ok(records)
}
/// 创建穿搭图片生成记录
#[tauri::command]
pub async fn create_outfit_image_record(
state: State<'_, AppState>,
request: OutfitImageGenerationRequest,
) -> Result<String, String> {
println!("🎨 创建穿搭图片生成记录: {:?}", request);
let database = state.get_database();
let outfit_repo = OutfitImageRepository::new(database);
// 创建生成记录
let mut record = OutfitImageRecord::new(
request.model_id,
request.model_image_id,
request.generation_prompt,
);
println!("📝 开始处理商品图片,共 {}", request.product_image_paths.len());
// 创建商品图片记录(使用异步文件操作)
for (index, product_path) in request.product_image_paths.iter().enumerate() {
println!("📷 处理商品图片 {}/{}: {}", index + 1, request.product_image_paths.len(), product_path);
let file_name = std::path::Path::new(product_path)
.file_name()
.and_then(|n| n.to_str())
.unwrap_or(&format!("product_{}", index))
.to_string();
// 使用异步文件操作,添加超时
let file_size = match tokio::time::timeout(
std::time::Duration::from_secs(5),
tokio::fs::metadata(product_path)
).await {
Ok(Ok(metadata)) => {
println!("📊 获取文件大小成功: {} bytes", metadata.len());
metadata.len()
},
Ok(Err(e)) => {
println!("⚠️ 获取文件元数据失败: {}, 使用默认大小", e);
0
},
Err(_) => {
println!("⚠️ 获取文件元数据超时,使用默认大小");
0
}
};
let product_image = ProductImage::new(
record.id.clone(),
product_path.clone(),
file_name,
file_size,
);
record.product_images.push(product_image);
}
println!("💾 开始保存到数据库");
// 使用事务保存所有数据
match outfit_repo.create_record_with_products(&record) {
Ok(_) => {
println!("✅ 穿搭图片生成记录创建成功: {}", record.id);
Ok(record.id)
},
Err(e) => {
println!("❌ 创建穿搭图片记录失败: {}", e);
Err(format!("创建穿搭图片记录失败: {}", e))
}
}
}
/// 删除穿搭图片生成记录
#[tauri::command]
pub async fn delete_outfit_image_record(
state: State<'_, AppState>,
record_id: String,
) -> Result<(), String> {
println!("🗑️ 删除穿搭图片生成记录: {}", record_id);
let database = state.get_database();
let outfit_repo = OutfitImageRepository::new(database);
outfit_repo.delete_record(&record_id)
.map_err(|e| format!("删除穿搭图片记录失败: {}", e))?;
println!("✅ 穿搭图片生成记录删除成功");
Ok(())
}
/// 获取穿搭图片生成记录详情
#[tauri::command]
pub async fn get_outfit_image_record_detail(
state: State<'_, AppState>,
record_id: String,
) -> Result<Option<OutfitImageRecord>, String> {
println!("🔍 获取穿搭图片生成记录详情: {}", record_id);
let database = state.get_database();
let outfit_repo = OutfitImageRepository::new(database);
let record = outfit_repo.get_record_by_id(&record_id)
.map_err(|e| format!("获取穿搭图片记录详情失败: {}", e))?;
println!("✅ 穿搭图片生成记录详情获取成功");
Ok(record)
}