| """ |
| Utility functions for ACE-Step application |
| """ |
|
|
| import logging |
| import yaml |
| from pathlib import Path |
| from typing import Dict, Any |
| import sys |
|
|
|
|
| def setup_logging(log_level: str = "INFO") -> logging.Logger: |
| """ |
| Setup logging configuration. |
| |
| Args: |
| log_level: Logging level |
| |
| Returns: |
| Logger instance |
| """ |
| |
| log_dir = Path("logs") |
| log_dir.mkdir(exist_ok=True) |
| |
| |
| logging.basicConfig( |
| level=getattr(logging, log_level), |
| format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', |
| handlers=[ |
| logging.FileHandler(log_dir / "ace_step.log"), |
| logging.StreamHandler(sys.stdout) |
| ] |
| ) |
| |
| logger = logging.getLogger("ace_step") |
| logger.info("Logging initialized") |
| |
| return logger |
|
|
|
|
| def load_config(config_path: str = "config.yaml") -> Dict[str, Any]: |
| """ |
| Load configuration from YAML file. |
| |
| Args: |
| config_path: Path to config file |
| |
| Returns: |
| Configuration dictionary |
| """ |
| config_file = Path(config_path) |
| |
| if config_file.exists(): |
| with open(config_file, 'r') as f: |
| config = yaml.safe_load(f) |
| else: |
| |
| config = { |
| "checkpoint_dir": "./checkpoints", |
| "dit_model_path": "acestep-v15-turbo", |
| "lm_model_path": "acestep-5Hz-lm-1.7B", |
| "model_path": "ACE-Step/ACE-Step-v1-3.5B", |
| "sample_rate": 44100, |
| "output_dir": "outputs", |
| "timeline_dir": "timelines", |
| "training_dir": "lora_training", |
| "chunk_duration": 30, |
| "force_mono": False, |
| "device": "auto", |
| "use_flash_attention": False, |
| "offload_to_cpu": False |
| } |
| |
| |
| with open(config_file, 'w') as f: |
| yaml.dump(config, f, default_flow_style=False) |
| |
| return config |
|
|
|
|
| def format_duration(seconds: float) -> str: |
| """ |
| Format duration in seconds to human-readable string. |
| |
| Args: |
| seconds: Duration in seconds |
| |
| Returns: |
| Formatted string (e.g., "2:30") |
| """ |
| minutes = int(seconds // 60) |
| secs = int(seconds % 60) |
| return f"{minutes}:{secs:02d}" |
|
|
|
|
| def validate_audio_file(file_path: str) -> bool: |
| """ |
| Validate audio file. |
| |
| Args: |
| file_path: Path to audio file |
| |
| Returns: |
| True if valid, False otherwise |
| """ |
| import torchaudio |
| |
| try: |
| audio, sr = torchaudio.load(file_path) |
| return True |
| except: |
| return False |
|
|
|
|
| def get_audio_info(file_path: str) -> Dict[str, Any]: |
| """ |
| Get audio file information. |
| |
| Args: |
| file_path: Path to audio file |
| |
| Returns: |
| Dictionary with audio info |
| """ |
| import torchaudio |
| |
| try: |
| audio, sr = torchaudio.load(file_path) |
| |
| return { |
| "duration": audio.shape[1] / sr, |
| "sample_rate": sr, |
| "channels": audio.shape[0], |
| "samples": audio.shape[1], |
| "format": Path(file_path).suffix |
| } |
| except Exception as e: |
| return {"error": str(e)} |
|
|
|
|
| def ensure_directories(): |
| """Create necessary directories if they don't exist.""" |
| dirs = ["outputs", "timelines", "lora_training", "logs", "models"] |
| |
| for dir_name in dirs: |
| Path(dir_name).mkdir(exist_ok=True) |
|
|