""" Enhanced MagicArticulate包装器 集成MagicArticulate-Plus用户上传支持 基于我们已完善的articulate_api.py """ import os import sys import time import logging import tempfile from pathlib import Path from typing import Optional, Dict, Any, Tuple, List # 添加必要的路径 parent_dir = os.path.join(os.path.dirname(__file__), '..') sys.path.append(parent_dir) # 添加mvp-space根目录 sys.path.append(os.path.join(parent_dir, 'magic_articulate_plus')) # 详细的调试信息 print(f"🔍 DEBUG: Current working directory: {os.getcwd()}") print(f"🔍 DEBUG: Script directory: {os.path.dirname(__file__)}") print(f"🔍 DEBUG: Parent directory: {parent_dir}") print(f"🔍 DEBUG: Python path includes:") for i, path in enumerate(sys.path): print(f" {i}: {path}") # 检查关键目录是否存在 utils_dir = os.path.join(parent_dir, 'utils') magic_plus_dir = os.path.join(parent_dir, 'magic_articulate_plus') skeleton_dir = os.path.join(parent_dir, 'skeleton_models') print(f"🔍 DEBUG: Directory existence:") print(f" utils directory exists: {os.path.exists(utils_dir)}") print(f" magic_articulate_plus directory exists: {os.path.exists(magic_plus_dir)}") print(f" skeleton_models directory exists: {os.path.exists(skeleton_dir)}") if os.path.exists(utils_dir): print(f"🔍 DEBUG: utils directory contents: {os.listdir(utils_dir)}") if os.path.exists(magic_plus_dir): print(f"🔍 DEBUG: magic_articulate_plus directory contents: {os.listdir(magic_plus_dir)}") # 导入我们已经完善的MagicArticulate-Plus功能 try: print("🔍 DEBUG: Attempting to import magic_articulate_plus.articulate_api...") from magic_articulate_plus.articulate_api import ( MagicArticulateAPI, ModelValidator, process_model_file ) print("✅ DEBUG: Successfully imported MagicArticulate-Plus components") ENHANCED_AVAILABLE = True except ImportError as e: print(f"❌ DEBUG: Import failed with error: {e}") print(f"❌ DEBUG: Error type: {type(e)}") import traceback print(f"❌ DEBUG: Full traceback:") traceback.print_exc() logging.warning(f"MagicArticulate-Plus not available: {e}") ENHANCED_AVAILABLE = False # 配置日志 logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) class EnhancedMagicWrapper: """ 增强版MagicArticulate包装器 支持用户上传任意3D模型文件 """ def __init__(self, model_weights_path: Optional[str] = None): # 如果没有指定权重路径,使用默认的空间模型(匹配demo.py hier_order=False) if model_weights_path is None: model_weights_path = "skeleton_ckpt/checkpoint_trainonv2_spatial.pth" self.model_weights_path = model_weights_path self.initialized = False if ENHANCED_AVAILABLE: # 使用我们完善的MagicArticulate-Plus API self.api = MagicArticulateAPI( model_weights_path=model_weights_path, device="auto", session_base_dir="hf_user_sessions" ) logger.info(f"✅ 使用增强版MagicArticulate-Plus API (weights: {model_weights_path})") else: # 降级到原始包装器 logger.error("❌ MagicArticulate-Plus不可用,请检查集成") self.api = None def initialize(self) -> bool: """初始化API""" try: if not ENHANCED_AVAILABLE: logger.error("增强版API不可用") return False logger.info("🚀 初始化增强版MagicArticulate...") # 使用我们已经完善的初始化逻辑 success = self.api.initialize_model() if success: self.initialized = True logger.info("✅ 增强版MagicArticulate初始化成功") else: logger.error("❌ 增强版MagicArticulate初始化失败") return success except Exception as e: logger.error(f"💥 初始化失败: {str(e)}") return False def validate_uploaded_file(self, file_path: str) -> Tuple[bool, str, Dict[str, Any]]: """ 验证用户上传的文件 使用我们已完善的ModelValidator """ try: if not ENHANCED_AVAILABLE: return False, "增强功能不可用", {} # 使用我们已经完善的验证逻辑 is_valid, error_msg, model_info = ModelValidator.validate_file(file_path) if is_valid: logger.info(f"✅ 文件验证通过: {model_info.get('file_name', 'Unknown')}") else: logger.warning(f"⚠️ 文件验证失败: {error_msg}") return is_valid, error_msg, model_info except Exception as e: error_msg = f"文件验证过程出错: {str(e)}" logger.error(error_msg) return False, error_msg, {} def process_3d_model(self, model_file_path: str, prompt: str = "", confidence_threshold: float = 0.8, generate_preview: bool = True, **kwargs) -> Dict[str, Any]: """ 处理3D模型 - 支持用户上传 使用我们已完善的处理管道 """ try: if not self.initialized: return { 'success': False, 'error': 'API未初始化', 'skeleton_data': None, 'output_files': None, 'processing_info': None } if not ENHANCED_AVAILABLE: return { 'success': False, 'error': '增强功能不可用', 'skeleton_data': None, 'output_files': None, 'processing_info': None } logger.info(f"🔄 开始处理用户上传的模型: {model_file_path}") # 首先验证文件 is_valid, error_msg, model_info = self.validate_uploaded_file(model_file_path) if not is_valid: return { 'success': False, 'error': f'文件验证失败: {error_msg}', 'skeleton_data': None, 'output_files': None, 'processing_info': model_info } # 准备处理选项 processing_options = { 'auto_repair': kwargs.get('auto_repair', True), 'target_faces': kwargs.get('target_faces', 10000), 'confidence_threshold': confidence_threshold, 'generate_preview': generate_preview } # 使用我们已完善的处理API result = self.api.process_uploaded_model( file_path=model_file_path, user_prompt=prompt, processing_options=processing_options ) # 转换为MVP期望的格式 if result['success']: logger.info("✅ 模型处理完成") # 添加处理信息 processing_info = { 'input_file': model_info.get('file_name', 'Unknown'), 'prompt': prompt, 'joint_count': result['skeleton_data'].get('joint_count', 0), 'bone_count': result['skeleton_data'].get('bone_count', 0), 'confidence_threshold': confidence_threshold, 'vertex_count': model_info.get('vertex_count', 0), 'face_count': model_info.get('face_count', 0), 'file_size_mb': model_info.get('file_size_mb', 0), 'preprocessing_log': result.get('preprocessing_log', []) } return { 'success': True, 'skeleton_data': result['skeleton_data'], 'output_files': result['output_files'], 'processing_info': processing_info } else: logger.error(f"❌ 处理失败: {result.get('error', 'Unknown error')}") return { 'success': False, 'error': result.get('error', 'Unknown error'), 'skeleton_data': None, 'output_files': None, 'processing_info': None } except Exception as e: error_msg = f"处理过程中发生错误: {str(e)}" logger.error(f"💥 {error_msg}") return { 'success': False, 'error': error_msg, 'skeleton_data': None, 'output_files': None, 'processing_info': None } def get_supported_formats(self) -> List[str]: """获取支持的文件格式""" if ENHANCED_AVAILABLE: # 返回我们已完善的格式列表 return list(ModelValidator.SUPPORTED_FORMATS) else: # 降级到基础格式 return ['.obj', '.glb', '.ply', '.stl'] def get_session_info(self, session_id: str) -> Dict[str, Any]: """获取会话信息""" try: if self.api and hasattr(self.api, 'get_session_info'): return self.api.get_session_info(session_id) else: return {} except Exception as e: logger.error(f"获取会话信息失败: {str(e)}") return {} def cleanup_sessions(self, max_age_days: int = 1): """清理旧会话(HF Space内存限制)""" try: if self.api and hasattr(self.api, 'cleanup_sessions'): self.api.cleanup_sessions(max_age_days) logger.info(f"✅ 清理了超过 {max_age_days} 天的旧会话") except Exception as e: logger.error(f"清理会话失败: {str(e)}") # 为了保持兼容性,提供原始类名的别名 MagicArticulateWrapper = EnhancedMagicWrapper # 简化的处理函数,直接使用我们完善的API def process_user_model(file_path: str, prompt: str = "", model_weights_path: Optional[str] = None) -> Dict[str, Any]: """ 简化的用户模型处理接口 直接使用我们已完善的process_model_file函数 """ try: if ENHANCED_AVAILABLE: # 使用我们已完善的简化接口 return process_model_file( file_path=file_path, user_prompt=prompt, model_weights_path=model_weights_path, output_dir="hf_temp_sessions" ) else: return { 'success': False, 'error': 'Enhanced API not available' } except Exception as e: return { 'success': False, 'error': f'Processing failed: {str(e)}' }