Spaces:
Paused
Paused
Update acestep/inference.py
Browse files- acestep/inference.py +12 -71
acestep/inference.py
CHANGED
|
@@ -11,10 +11,8 @@ from loguru import logger
|
|
| 11 |
import torch
|
| 12 |
from acestep.audio_utils import AudioSaver, generate_uuid_from_params
|
| 13 |
|
| 14 |
-
# HuggingFace Space environment detection
|
| 15 |
IS_HUGGINGFACE_SPACE = os.environ.get("SPACE_ID") is not None
|
| 16 |
|
| 17 |
-
# تعریف کلاس اختصاصی برای خروج امن قبل از اتمام محدودیت ۱۲۰ ثانیهای
|
| 18 |
class TimeoutSavedException(Exception):
|
| 19 |
def __init__(self, task_id: str, step: int):
|
| 20 |
self.task_id = task_id
|
|
@@ -23,31 +21,19 @@ class TimeoutSavedException(Exception):
|
|
| 23 |
|
| 24 |
@dataclass
|
| 25 |
class GenerationParams:
|
| 26 |
-
"""Configuration for music generation parameters."""
|
| 27 |
-
# Required Inputs
|
| 28 |
task_type: str = "text2music"
|
| 29 |
instruction: str = "Fill the audio semantic mask based on the given conditions:"
|
| 30 |
-
|
| 31 |
-
# Audio Uploads
|
| 32 |
reference_audio: Optional[str] = None
|
| 33 |
src_audio: Optional[str] = None
|
| 34 |
-
|
| 35 |
-
# LM Codes Hints
|
| 36 |
audio_codes: str = ""
|
| 37 |
-
|
| 38 |
-
# Text Inputs
|
| 39 |
caption: str = ""
|
| 40 |
lyrics: str = ""
|
| 41 |
instrumental: bool = False
|
| 42 |
-
|
| 43 |
-
# Metadata
|
| 44 |
vocal_language: str = "unknown"
|
| 45 |
bpm: Optional[int] = None
|
| 46 |
keyscale: str = ""
|
| 47 |
timesignature: str = ""
|
| 48 |
duration: float = -1.0
|
| 49 |
-
|
| 50 |
-
# Advanced Settings
|
| 51 |
inference_steps: int = 8
|
| 52 |
seed: int = -1
|
| 53 |
guidance_scale: float = 7.0
|
|
@@ -55,14 +41,11 @@ class GenerationParams:
|
|
| 55 |
cfg_interval_start: float = 0.0
|
| 56 |
cfg_interval_end: float = 1.0
|
| 57 |
shift: float = 1.0
|
| 58 |
-
infer_method: str = "ode"
|
| 59 |
timesteps: Optional[List[float]] = None
|
| 60 |
-
|
| 61 |
repainting_start: float = 0.0
|
| 62 |
repainting_end: float = -1
|
| 63 |
audio_cover_strength: float = 1.0
|
| 64 |
-
|
| 65 |
-
# 5Hz Language Model Parameters
|
| 66 |
thinking: bool = True
|
| 67 |
lm_temperature: float = 0.85
|
| 68 |
lm_cfg_scale: float = 2.0
|
|
@@ -71,10 +54,9 @@ class GenerationParams:
|
|
| 71 |
lm_negative_prompt: str = "NO USER INPUT"
|
| 72 |
use_cot_metas: bool = True
|
| 73 |
use_cot_caption: bool = True
|
| 74 |
-
use_cot_lyrics: bool = False
|
| 75 |
use_cot_language: bool = True
|
| 76 |
use_constrained_decoding: bool = True
|
| 77 |
-
|
| 78 |
cot_bpm: Optional[int] = None
|
| 79 |
cot_keyscale: str = ""
|
| 80 |
cot_timesignature: str = ""
|
|
@@ -82,34 +64,26 @@ class GenerationParams:
|
|
| 82 |
cot_vocal_language: str = "unknown"
|
| 83 |
cot_caption: str = ""
|
| 84 |
cot_lyrics: str = ""
|
| 85 |
-
|
| 86 |
-
# شناسه ذخیره و احیا
|
| 87 |
task_id: Optional[str] = None
|
| 88 |
|
| 89 |
def to_dict(self) -> Dict[str, Any]:
|
| 90 |
-
"""Convert config to dictionary for JSON serialization."""
|
| 91 |
return asdict(self)
|
| 92 |
|
| 93 |
-
|
| 94 |
@dataclass
|
| 95 |
class GenerationConfig:
|
| 96 |
-
"""Configuration for music generation."""
|
| 97 |
batch_size: int = 2
|
| 98 |
allow_lm_batch: bool = False
|
| 99 |
use_random_seed: bool = True
|
| 100 |
seeds: Optional[List[int]] = None
|
| 101 |
lm_batch_chunk_size: int = 8
|
| 102 |
constrained_decoding_debug: bool = False
|
| 103 |
-
audio_format: str = "flac"
|
| 104 |
|
| 105 |
def to_dict(self) -> Dict[str, Any]:
|
| 106 |
-
"""Convert config to dictionary for JSON serialization."""
|
| 107 |
return asdict(self)
|
| 108 |
|
| 109 |
-
|
| 110 |
@dataclass
|
| 111 |
class GenerationResult:
|
| 112 |
-
"""Result of music generation."""
|
| 113 |
audios: List[Dict[str, Any]] = field(default_factory=list)
|
| 114 |
status_message: str = ""
|
| 115 |
extra_outputs: Dict[str, Any] = field(default_factory=dict)
|
|
@@ -117,13 +91,10 @@ class GenerationResult:
|
|
| 117 |
error: Optional[str] = None
|
| 118 |
|
| 119 |
def to_dict(self) -> Dict[str, Any]:
|
| 120 |
-
"""Convert result to dictionary for JSON serialization."""
|
| 121 |
return asdict(self)
|
| 122 |
|
| 123 |
-
|
| 124 |
@dataclass
|
| 125 |
class UnderstandResult:
|
| 126 |
-
"""Result of music understanding from audio codes."""
|
| 127 |
caption: str = ""
|
| 128 |
lyrics: str = ""
|
| 129 |
bpm: Optional[int] = None
|
|
@@ -136,13 +107,10 @@ class UnderstandResult:
|
|
| 136 |
error: Optional[str] = None
|
| 137 |
|
| 138 |
def to_dict(self) -> Dict[str, Any]:
|
| 139 |
-
"""Convert result to dictionary for JSON serialization."""
|
| 140 |
return asdict(self)
|
| 141 |
|
| 142 |
-
|
| 143 |
@dataclass
|
| 144 |
class CreateSampleResult:
|
| 145 |
-
"""Result of creating a music sample from a natural language query."""
|
| 146 |
caption: str = ""
|
| 147 |
lyrics: str = ""
|
| 148 |
bpm: Optional[int] = None
|
|
@@ -156,13 +124,10 @@ class CreateSampleResult:
|
|
| 156 |
error: Optional[str] = None
|
| 157 |
|
| 158 |
def to_dict(self) -> Dict[str, Any]:
|
| 159 |
-
"""Convert result to dictionary for JSON serialization."""
|
| 160 |
return asdict(self)
|
| 161 |
|
| 162 |
-
|
| 163 |
@dataclass
|
| 164 |
class FormatSampleResult:
|
| 165 |
-
"""Result of formatting user-provided caption and lyrics."""
|
| 166 |
caption: str = ""
|
| 167 |
lyrics: str = ""
|
| 168 |
bpm: Optional[int] = None
|
|
@@ -175,10 +140,8 @@ class FormatSampleResult:
|
|
| 175 |
error: Optional[str] = None
|
| 176 |
|
| 177 |
def to_dict(self) -> Dict[str, Any]:
|
| 178 |
-
"""Convert result to dictionary for JSON serialization."""
|
| 179 |
return asdict(self)
|
| 180 |
|
| 181 |
-
|
| 182 |
def _update_metadata_from_lm(
|
| 183 |
metadata: Dict[str, Any],
|
| 184 |
bpm: Optional[int],
|
|
@@ -189,7 +152,6 @@ def _update_metadata_from_lm(
|
|
| 189 |
caption: str,
|
| 190 |
lyrics: str,
|
| 191 |
) -> Tuple[Optional[int], str, str, Optional[float], str, str, str]:
|
| 192 |
-
"""Update metadata fields from LM output if not provided by user."""
|
| 193 |
if bpm is None and metadata.get('bpm'):
|
| 194 |
bpm_value = metadata.get('bpm')
|
| 195 |
if bpm_value not in ["N/A", ""]:
|
|
@@ -224,7 +186,6 @@ def _update_metadata_from_lm(
|
|
| 224 |
lyrics = metadata.get('lyrics')
|
| 225 |
return bpm, key_scale, time_signature, audio_duration, vocal_language, caption, lyrics
|
| 226 |
|
| 227 |
-
|
| 228 |
def generate_music(
|
| 229 |
dit_handler,
|
| 230 |
llm_handler,
|
|
@@ -233,7 +194,6 @@ def generate_music(
|
|
| 233 |
save_dir: Optional[str] = None,
|
| 234 |
progress=None,
|
| 235 |
) -> GenerationResult:
|
| 236 |
-
"""Generate music using ACE-Step model with optional LM reasoning."""
|
| 237 |
try:
|
| 238 |
audio_code_string_to_use = params.audio_codes
|
| 239 |
lm_generated_metadata = None
|
|
@@ -244,7 +204,6 @@ def generate_music(
|
|
| 244 |
"total_time": 0.0,
|
| 245 |
}
|
| 246 |
|
| 247 |
-
# Extract mutable copies of metadata
|
| 248 |
bpm = params.bpm
|
| 249 |
key_scale = params.keyscale
|
| 250 |
time_signature = params.timesignature
|
|
@@ -257,42 +216,37 @@ def generate_music(
|
|
| 257 |
need_audio_codes = not user_provided_audio_codes
|
| 258 |
actual_batch_size = config.batch_size if config.batch_size is not None else 1
|
| 259 |
|
| 260 |
-
# تعیین روت دایرکتوری پایدار برای ذخیره لیتنتها
|
| 261 |
storage_root = "/data" if os.path.exists("/data") else tempfile.gettempdir()
|
| 262 |
resume_dir = os.path.join(storage_root, "resume_tasks")
|
| 263 |
os.makedirs(resume_dir, exist_ok=True)
|
| 264 |
|
| 265 |
-
# بررسی هوشمند فیلد Seed برای استخراج شناسه احیا (Tracking ID)
|
| 266 |
active_task_id = params.task_id
|
| 267 |
is_resumed_run = False
|
| 268 |
|
| 269 |
-
# اگر کاربر شناسه احیا را به جای Seed وارد کرده باشد (غیر عددی بودن سید)
|
| 270 |
if isinstance(params.seed, str) and params.seed.strip():
|
| 271 |
cleaned_seed = params.seed.strip()
|
| 272 |
if not cleaned_seed.replace("-", "").replace(",", "").isdigit():
|
| 273 |
active_task_id = cleaned_seed
|
| 274 |
is_resumed_run = True
|
| 275 |
-
logger.info(f"
|
| 276 |
|
| 277 |
if not active_task_id or not active_task_id.strip():
|
| 278 |
active_task_id = str(uuid.uuid4())[:8]
|
| 279 |
|
| 280 |
params.task_id = active_task_id
|
| 281 |
|
| 282 |
-
# بررسی فیزیکی وجود وضعیت ذخیره شده بر روی دیسک
|
| 283 |
resume_path = os.path.join(resume_dir, f"{active_task_id}_latents.pt")
|
| 284 |
meta_path = os.path.join(resume_dir, f"{active_task_id}_meta.json")
|
| 285 |
|
| 286 |
if os.path.exists(resume_path) and os.path.exists(meta_path):
|
| 287 |
is_resumed_run = True
|
| 288 |
-
logger.info(f"
|
| 289 |
|
| 290 |
seed_for_generation = ""
|
| 291 |
if config.seeds is not None and len(config.seeds) > 0:
|
| 292 |
if isinstance(config.seeds, list):
|
| 293 |
seed_for_generation = ",".join(str(s) for s in config.seeds)
|
| 294 |
|
| 295 |
-
# اگر در حالت احیا هستیم، از ساخت سیدهای تصادفی جدید عبور میکنیم تا شرایط ثابت بماند
|
| 296 |
if is_resumed_run:
|
| 297 |
config.use_random_seed = False
|
| 298 |
if os.path.exists(meta_path):
|
|
@@ -308,7 +262,6 @@ def generate_music(
|
|
| 308 |
|
| 309 |
actual_seed_list, _ = dit_handler.prepare_seeds(actual_batch_size, seed_for_generation, config.use_random_seed)
|
| 310 |
|
| 311 |
-
# ذخیره سیدها در ابتدای فاز یک برای بازیابیهای احتمالی بعدی در فاز دو
|
| 312 |
if not is_resumed_run:
|
| 313 |
temp_meta_save = os.path.join(resume_dir, f"{active_task_id}_meta.json")
|
| 314 |
try:
|
|
@@ -317,7 +270,6 @@ def generate_music(
|
|
| 317 |
except Exception as e:
|
| 318 |
logger.error(f"Failed to pre-save meta seeds: {e}")
|
| 319 |
|
| 320 |
-
# بارگذاری مجدد دیتای متادیتا در فاز یک در صورت احیا شدن
|
| 321 |
if is_resumed_run and os.path.exists(meta_path):
|
| 322 |
try:
|
| 323 |
with open(meta_path, 'r', encoding='utf-8') as f:
|
|
@@ -325,7 +277,7 @@ def generate_music(
|
|
| 325 |
saved_lm_metadata = meta_data.get("lm_metadata")
|
| 326 |
if saved_lm_metadata:
|
| 327 |
lm_generated_metadata = saved_lm_metadata
|
| 328 |
-
logger.info(f"
|
| 329 |
except Exception as e:
|
| 330 |
logger.error(f"Failed to restore metadata from meta file: {e}")
|
| 331 |
|
|
@@ -473,7 +425,6 @@ def generate_music(
|
|
| 473 |
if params.use_cot_language:
|
| 474 |
dit_input_vocal_language = lm_generated_metadata.get("vocal_language", dit_input_vocal_language)
|
| 475 |
|
| 476 |
-
# ذخیره کردن وضعیت متا برای ب��زیابی در فاز دو
|
| 477 |
temp_meta_save = os.path.join(resume_dir, f"{active_task_id}_meta.json")
|
| 478 |
try:
|
| 479 |
with open(temp_meta_save, 'w', encoding='utf-8') as f:
|
|
@@ -486,14 +437,13 @@ def generate_music(
|
|
| 486 |
except Exception as e:
|
| 487 |
logger.error(f"Failed to save temporary CoT meta: {e}")
|
| 488 |
|
| 489 |
-
#
|
| 490 |
decoder = dit_handler.model.decoder
|
| 491 |
original_forward = decoder.forward
|
| 492 |
current_step = 0
|
| 493 |
-
timeout_limit = 95.0
|
| 494 |
fsm_start_time = time.time()
|
| 495 |
|
| 496 |
-
# بازیابی لیتنتهای ذخیره شده قبلی و همگامسازی گام شروع
|
| 497 |
is_resumed_run_active = False
|
| 498 |
resume_step_idx = 0
|
| 499 |
saved_latents_tensor = None
|
|
@@ -505,35 +455,29 @@ def generate_music(
|
|
| 505 |
resume_step_idx = meta_data.get("resume_step", 0)
|
| 506 |
saved_latents_tensor = torch.load(resume_path, map_location='cpu')
|
| 507 |
is_resumed_run_active = True
|
| 508 |
-
logger.info(f"
|
| 509 |
except Exception as e:
|
| 510 |
-
logger.error(f"
|
| 511 |
is_resumed_run_active = False
|
| 512 |
|
| 513 |
def patched_forward(self_decoder, hidden_states, timestep, *args, **kwargs):
|
| 514 |
nonlocal current_step, fsm_start_time, is_resumed_run_active, resume_step_idx, saved_latents_tensor, active_task_id
|
| 515 |
|
| 516 |
-
# اگر در مرحله احیا هستیم و هنوز به گام ذخیره شده نرسیدهایم، فورا از پردازش گام عبور کن
|
| 517 |
if is_resumed_run_active and current_step < resume_step_idx:
|
| 518 |
current_step += 1
|
| 519 |
return (torch.zeros_like(hidden_states),)
|
| 520 |
|
| 521 |
-
# اگر دقیقاً به گام قطع شده رسیدیم، لیتنتهای قبلی را به VRAM تزریق کن
|
| 522 |
if is_resumed_run_active and current_step == resume_step_idx:
|
| 523 |
saved_latents_tensor = saved_latents_tensor.to(device=hidden_states.device, dtype=hidden_states.dtype)
|
| 524 |
hidden_states.copy_(saved_latents_tensor)
|
| 525 |
is_resumed_run_active = False
|
| 526 |
-
logger.info(f"
|
| 527 |
|
| 528 |
-
# محاسبه زمان باقیمانده برای فرار از تایم اوت
|
| 529 |
elapsed_time = time.time() - fsm_start_time
|
| 530 |
if elapsed_time > timeout_limit:
|
| 531 |
-
logger.warning(f"
|
| 532 |
-
|
| 533 |
-
# انتقال لیتنتها به CPU و ذخیره روی هارد پایدار
|
| 534 |
torch.save(hidden_states.cpu(), resume_path)
|
| 535 |
|
| 536 |
-
# بروزرسانی فایل متا
|
| 537 |
current_meta = {"task_id": active_task_id, "resume_step": current_step, "seeds": actual_seed_list}
|
| 538 |
if lm_generated_metadata:
|
| 539 |
current_meta["lm_metadata"] = lm_generated_metadata
|
|
@@ -541,7 +485,6 @@ def generate_music(
|
|
| 541 |
with open(meta_path, 'w', encoding='utf-8') as f:
|
| 542 |
json.dump(current_meta, f, ensure_ascii=False)
|
| 543 |
|
| 544 |
-
# بازیابی فوری متد اصلی دکودر
|
| 545 |
decoder.forward = original_forward
|
| 546 |
raise TimeoutSavedException(active_task_id, current_step)
|
| 547 |
|
|
@@ -585,7 +528,6 @@ def generate_music(
|
|
| 585 |
finally:
|
| 586 |
decoder.forward = original_forward
|
| 587 |
|
| 588 |
-
# در صورت اتمام موفقیتآمیز رندر، فایلهای ذخیره وضعیت میانی را برای پاکیزگی دیسک حذف کن
|
| 589 |
if os.path.exists(resume_path):
|
| 590 |
try:
|
| 591 |
os.remove(resume_path)
|
|
@@ -690,7 +632,6 @@ def generate_music(
|
|
| 690 |
)
|
| 691 |
|
| 692 |
except TimeoutSavedException as e:
|
| 693 |
-
# مدیریت استثنای قطع امن و پرتاب آن به سمت لایه بالاتر
|
| 694 |
raise e
|
| 695 |
except Exception as e:
|
| 696 |
logger.exception("Music generation failed")
|
|
|
|
| 11 |
import torch
|
| 12 |
from acestep.audio_utils import AudioSaver, generate_uuid_from_params
|
| 13 |
|
|
|
|
| 14 |
IS_HUGGINGFACE_SPACE = os.environ.get("SPACE_ID") is not None
|
| 15 |
|
|
|
|
| 16 |
class TimeoutSavedException(Exception):
|
| 17 |
def __init__(self, task_id: str, step: int):
|
| 18 |
self.task_id = task_id
|
|
|
|
| 21 |
|
| 22 |
@dataclass
|
| 23 |
class GenerationParams:
|
|
|
|
|
|
|
| 24 |
task_type: str = "text2music"
|
| 25 |
instruction: str = "Fill the audio semantic mask based on the given conditions:"
|
|
|
|
|
|
|
| 26 |
reference_audio: Optional[str] = None
|
| 27 |
src_audio: Optional[str] = None
|
|
|
|
|
|
|
| 28 |
audio_codes: str = ""
|
|
|
|
|
|
|
| 29 |
caption: str = ""
|
| 30 |
lyrics: str = ""
|
| 31 |
instrumental: bool = False
|
|
|
|
|
|
|
| 32 |
vocal_language: str = "unknown"
|
| 33 |
bpm: Optional[int] = None
|
| 34 |
keyscale: str = ""
|
| 35 |
timesignature: str = ""
|
| 36 |
duration: float = -1.0
|
|
|
|
|
|
|
| 37 |
inference_steps: int = 8
|
| 38 |
seed: int = -1
|
| 39 |
guidance_scale: float = 7.0
|
|
|
|
| 41 |
cfg_interval_start: float = 0.0
|
| 42 |
cfg_interval_end: float = 1.0
|
| 43 |
shift: float = 1.0
|
| 44 |
+
infer_method: str = "ode"
|
| 45 |
timesteps: Optional[List[float]] = None
|
|
|
|
| 46 |
repainting_start: float = 0.0
|
| 47 |
repainting_end: float = -1
|
| 48 |
audio_cover_strength: float = 1.0
|
|
|
|
|
|
|
| 49 |
thinking: bool = True
|
| 50 |
lm_temperature: float = 0.85
|
| 51 |
lm_cfg_scale: float = 2.0
|
|
|
|
| 54 |
lm_negative_prompt: str = "NO USER INPUT"
|
| 55 |
use_cot_metas: bool = True
|
| 56 |
use_cot_caption: bool = True
|
| 57 |
+
use_cot_lyrics: bool = False
|
| 58 |
use_cot_language: bool = True
|
| 59 |
use_constrained_decoding: bool = True
|
|
|
|
| 60 |
cot_bpm: Optional[int] = None
|
| 61 |
cot_keyscale: str = ""
|
| 62 |
cot_timesignature: str = ""
|
|
|
|
| 64 |
cot_vocal_language: str = "unknown"
|
| 65 |
cot_caption: str = ""
|
| 66 |
cot_lyrics: str = ""
|
|
|
|
|
|
|
| 67 |
task_id: Optional[str] = None
|
| 68 |
|
| 69 |
def to_dict(self) -> Dict[str, Any]:
|
|
|
|
| 70 |
return asdict(self)
|
| 71 |
|
|
|
|
| 72 |
@dataclass
|
| 73 |
class GenerationConfig:
|
|
|
|
| 74 |
batch_size: int = 2
|
| 75 |
allow_lm_batch: bool = False
|
| 76 |
use_random_seed: bool = True
|
| 77 |
seeds: Optional[List[int]] = None
|
| 78 |
lm_batch_chunk_size: int = 8
|
| 79 |
constrained_decoding_debug: bool = False
|
| 80 |
+
audio_format: str = "flac"
|
| 81 |
|
| 82 |
def to_dict(self) -> Dict[str, Any]:
|
|
|
|
| 83 |
return asdict(self)
|
| 84 |
|
|
|
|
| 85 |
@dataclass
|
| 86 |
class GenerationResult:
|
|
|
|
| 87 |
audios: List[Dict[str, Any]] = field(default_factory=list)
|
| 88 |
status_message: str = ""
|
| 89 |
extra_outputs: Dict[str, Any] = field(default_factory=dict)
|
|
|
|
| 91 |
error: Optional[str] = None
|
| 92 |
|
| 93 |
def to_dict(self) -> Dict[str, Any]:
|
|
|
|
| 94 |
return asdict(self)
|
| 95 |
|
|
|
|
| 96 |
@dataclass
|
| 97 |
class UnderstandResult:
|
|
|
|
| 98 |
caption: str = ""
|
| 99 |
lyrics: str = ""
|
| 100 |
bpm: Optional[int] = None
|
|
|
|
| 107 |
error: Optional[str] = None
|
| 108 |
|
| 109 |
def to_dict(self) -> Dict[str, Any]:
|
|
|
|
| 110 |
return asdict(self)
|
| 111 |
|
|
|
|
| 112 |
@dataclass
|
| 113 |
class CreateSampleResult:
|
|
|
|
| 114 |
caption: str = ""
|
| 115 |
lyrics: str = ""
|
| 116 |
bpm: Optional[int] = None
|
|
|
|
| 124 |
error: Optional[str] = None
|
| 125 |
|
| 126 |
def to_dict(self) -> Dict[str, Any]:
|
|
|
|
| 127 |
return asdict(self)
|
| 128 |
|
|
|
|
| 129 |
@dataclass
|
| 130 |
class FormatSampleResult:
|
|
|
|
| 131 |
caption: str = ""
|
| 132 |
lyrics: str = ""
|
| 133 |
bpm: Optional[int] = None
|
|
|
|
| 140 |
error: Optional[str] = None
|
| 141 |
|
| 142 |
def to_dict(self) -> Dict[str, Any]:
|
|
|
|
| 143 |
return asdict(self)
|
| 144 |
|
|
|
|
| 145 |
def _update_metadata_from_lm(
|
| 146 |
metadata: Dict[str, Any],
|
| 147 |
bpm: Optional[int],
|
|
|
|
| 152 |
caption: str,
|
| 153 |
lyrics: str,
|
| 154 |
) -> Tuple[Optional[int], str, str, Optional[float], str, str, str]:
|
|
|
|
| 155 |
if bpm is None and metadata.get('bpm'):
|
| 156 |
bpm_value = metadata.get('bpm')
|
| 157 |
if bpm_value not in ["N/A", ""]:
|
|
|
|
| 186 |
lyrics = metadata.get('lyrics')
|
| 187 |
return bpm, key_scale, time_signature, audio_duration, vocal_language, caption, lyrics
|
| 188 |
|
|
|
|
| 189 |
def generate_music(
|
| 190 |
dit_handler,
|
| 191 |
llm_handler,
|
|
|
|
| 194 |
save_dir: Optional[str] = None,
|
| 195 |
progress=None,
|
| 196 |
) -> GenerationResult:
|
|
|
|
| 197 |
try:
|
| 198 |
audio_code_string_to_use = params.audio_codes
|
| 199 |
lm_generated_metadata = None
|
|
|
|
| 204 |
"total_time": 0.0,
|
| 205 |
}
|
| 206 |
|
|
|
|
| 207 |
bpm = params.bpm
|
| 208 |
key_scale = params.keyscale
|
| 209 |
time_signature = params.timesignature
|
|
|
|
| 216 |
need_audio_codes = not user_provided_audio_codes
|
| 217 |
actual_batch_size = config.batch_size if config.batch_size is not None else 1
|
| 218 |
|
|
|
|
| 219 |
storage_root = "/data" if os.path.exists("/data") else tempfile.gettempdir()
|
| 220 |
resume_dir = os.path.join(storage_root, "resume_tasks")
|
| 221 |
os.makedirs(resume_dir, exist_ok=True)
|
| 222 |
|
|
|
|
| 223 |
active_task_id = params.task_id
|
| 224 |
is_resumed_run = False
|
| 225 |
|
|
|
|
| 226 |
if isinstance(params.seed, str) and params.seed.strip():
|
| 227 |
cleaned_seed = params.seed.strip()
|
| 228 |
if not cleaned_seed.replace("-", "").replace(",", "").isdigit():
|
| 229 |
active_task_id = cleaned_seed
|
| 230 |
is_resumed_run = True
|
| 231 |
+
logger.info(f"Resuming request from Seed-Input Tracking ID: {active_task_id}")
|
| 232 |
|
| 233 |
if not active_task_id or not active_task_id.strip():
|
| 234 |
active_task_id = str(uuid.uuid4())[:8]
|
| 235 |
|
| 236 |
params.task_id = active_task_id
|
| 237 |
|
|
|
|
| 238 |
resume_path = os.path.join(resume_dir, f"{active_task_id}_latents.pt")
|
| 239 |
meta_path = os.path.join(resume_dir, f"{active_task_id}_meta.json")
|
| 240 |
|
| 241 |
if os.path.exists(resume_path) and os.path.exists(meta_path):
|
| 242 |
is_resumed_run = True
|
| 243 |
+
logger.info(f"State files found for Task {active_task_id}")
|
| 244 |
|
| 245 |
seed_for_generation = ""
|
| 246 |
if config.seeds is not None and len(config.seeds) > 0:
|
| 247 |
if isinstance(config.seeds, list):
|
| 248 |
seed_for_generation = ",".join(str(s) for s in config.seeds)
|
| 249 |
|
|
|
|
| 250 |
if is_resumed_run:
|
| 251 |
config.use_random_seed = False
|
| 252 |
if os.path.exists(meta_path):
|
|
|
|
| 262 |
|
| 263 |
actual_seed_list, _ = dit_handler.prepare_seeds(actual_batch_size, seed_for_generation, config.use_random_seed)
|
| 264 |
|
|
|
|
| 265 |
if not is_resumed_run:
|
| 266 |
temp_meta_save = os.path.join(resume_dir, f"{active_task_id}_meta.json")
|
| 267 |
try:
|
|
|
|
| 270 |
except Exception as e:
|
| 271 |
logger.error(f"Failed to pre-save meta seeds: {e}")
|
| 272 |
|
|
|
|
| 273 |
if is_resumed_run and os.path.exists(meta_path):
|
| 274 |
try:
|
| 275 |
with open(meta_path, 'r', encoding='utf-8') as f:
|
|
|
|
| 277 |
saved_lm_metadata = meta_data.get("lm_metadata")
|
| 278 |
if saved_lm_metadata:
|
| 279 |
lm_generated_metadata = saved_lm_metadata
|
| 280 |
+
logger.info(f"Restored CoT Metadata for Task {active_task_id}")
|
| 281 |
except Exception as e:
|
| 282 |
logger.error(f"Failed to restore metadata from meta file: {e}")
|
| 283 |
|
|
|
|
| 425 |
if params.use_cot_language:
|
| 426 |
dit_input_vocal_language = lm_generated_metadata.get("vocal_language", dit_input_vocal_language)
|
| 427 |
|
|
|
|
| 428 |
temp_meta_save = os.path.join(resume_dir, f"{active_task_id}_meta.json")
|
| 429 |
try:
|
| 430 |
with open(temp_meta_save, 'w', encoding='utf-8') as f:
|
|
|
|
| 437 |
except Exception as e:
|
| 438 |
logger.error(f"Failed to save temporary CoT meta: {e}")
|
| 439 |
|
| 440 |
+
# اعمال دکوراتور داینامیک بر روی کلاس مدل
|
| 441 |
decoder = dit_handler.model.decoder
|
| 442 |
original_forward = decoder.forward
|
| 443 |
current_step = 0
|
| 444 |
+
timeout_limit = 95.0
|
| 445 |
fsm_start_time = time.time()
|
| 446 |
|
|
|
|
| 447 |
is_resumed_run_active = False
|
| 448 |
resume_step_idx = 0
|
| 449 |
saved_latents_tensor = None
|
|
|
|
| 455 |
resume_step_idx = meta_data.get("resume_step", 0)
|
| 456 |
saved_latents_tensor = torch.load(resume_path, map_location='cpu')
|
| 457 |
is_resumed_run_active = True
|
| 458 |
+
logger.info(f"Active. Will inject saved VRAM at step {resume_step_idx}")
|
| 459 |
except Exception as e:
|
| 460 |
+
logger.error(f"Restore failed: {e}")
|
| 461 |
is_resumed_run_active = False
|
| 462 |
|
| 463 |
def patched_forward(self_decoder, hidden_states, timestep, *args, **kwargs):
|
| 464 |
nonlocal current_step, fsm_start_time, is_resumed_run_active, resume_step_idx, saved_latents_tensor, active_task_id
|
| 465 |
|
|
|
|
| 466 |
if is_resumed_run_active and current_step < resume_step_idx:
|
| 467 |
current_step += 1
|
| 468 |
return (torch.zeros_like(hidden_states),)
|
| 469 |
|
|
|
|
| 470 |
if is_resumed_run_active and current_step == resume_step_idx:
|
| 471 |
saved_latents_tensor = saved_latents_tensor.to(device=hidden_states.device, dtype=hidden_states.dtype)
|
| 472 |
hidden_states.copy_(saved_latents_tensor)
|
| 473 |
is_resumed_run_active = False
|
| 474 |
+
logger.info(f"Successfully injected saved VRAM at step {current_step}")
|
| 475 |
|
|
|
|
| 476 |
elapsed_time = time.time() - fsm_start_time
|
| 477 |
if elapsed_time > timeout_limit:
|
| 478 |
+
logger.warning(f"Intercepted at {elapsed_time:.1f}s. Saving state for {active_task_id} at step {current_step}")
|
|
|
|
|
|
|
| 479 |
torch.save(hidden_states.cpu(), resume_path)
|
| 480 |
|
|
|
|
| 481 |
current_meta = {"task_id": active_task_id, "resume_step": current_step, "seeds": actual_seed_list}
|
| 482 |
if lm_generated_metadata:
|
| 483 |
current_meta["lm_metadata"] = lm_generated_metadata
|
|
|
|
| 485 |
with open(meta_path, 'w', encoding='utf-8') as f:
|
| 486 |
json.dump(current_meta, f, ensure_ascii=False)
|
| 487 |
|
|
|
|
| 488 |
decoder.forward = original_forward
|
| 489 |
raise TimeoutSavedException(active_task_id, current_step)
|
| 490 |
|
|
|
|
| 528 |
finally:
|
| 529 |
decoder.forward = original_forward
|
| 530 |
|
|
|
|
| 531 |
if os.path.exists(resume_path):
|
| 532 |
try:
|
| 533 |
os.remove(resume_path)
|
|
|
|
| 632 |
)
|
| 633 |
|
| 634 |
except TimeoutSavedException as e:
|
|
|
|
| 635 |
raise e
|
| 636 |
except Exception as e:
|
| 637 |
logger.exception("Music generation failed")
|