Spaces:
Runtime error
Runtime error
| import os, sys, torch, gradio as gr, tempfile, uuid, re, numpy as np, gc | |
| import torchaudio | |
| from torchaudio.transforms import Resample | |
| from omegaconf import OmegaConf | |
| from tqdm import tqdm | |
| from einops import rearrange | |
| from transformers import ( | |
| AutoTokenizer, AutoModelForCausalLM, | |
| LogitsProcessor, LogitsProcessorList | |
| ) | |
| from huggingface_hub import snapshot_download, login | |
| # ----------------- Hugging Face Authentication ----------------- | |
| HF_TOKEN = os.getenv("HF_TOKEN") # β Read securely from environment variable | |
| if HF_TOKEN: | |
| login(token=HF_TOKEN) | |
| print("π Logged into Hugging Face successfully.") | |
| else: | |
| print("β οΈ No Hugging Face token found. Please set it in your environment variables.") | |
| # ----------------- Basic Environment Setup ----------------- | |
| print("π§ Initializing environment (CPU mode)...") | |
| os.environ["PYTORCH_JIT"] = "0" | |
| torch.set_num_threads(1) | |
| torch.backends.cuda.matmul.allow_tf32 = False | |
| torch.backends.cudnn.benchmark = False | |
| device = "cpu" | |
| # ----------------- Model Download ----------------- | |
| folder_path = './xcodec_mini_infer' | |
| os.makedirs(folder_path, exist_ok=True) | |
| print(f"π¦ Folder ready: {folder_path}") | |
| snapshot_download( | |
| repo_id="m-a-p/xcodec_mini_infer", | |
| local_dir="./xcodec_mini_infer", | |
| token=HF_TOKEN | |
| ) | |
| sys.path.append(os.path.join(os.path.dirname(__file__), 'xcodec_mini_infer')) | |
| sys.path.append(os.path.join(os.path.dirname(__file__), 'xcodec_mini_infer', 'descriptaudiocodec')) | |
| from codecmanipulator import CodecManipulator | |
| from mmtokenizer import _MMSentencePieceTokenizer | |
| from models.soundstream_hubert_new import SoundStream | |
| # ----------------- Load YuE Model ----------------- | |
| print("π§ Loading YuE model on CPU (small version)...") | |
| try: | |
| model = AutoModelForCausalLM.from_pretrained( | |
| "m-a-p/YuE-upsampler", | |
| torch_dtype=torch.float32, | |
| attn_implementation="eager", | |
| low_cpu_mem_usage=True, | |
| device_map={"": "cpu"}, | |
| token=HF_TOKEN | |
| ) | |
| model.eval() | |
| print("β YuE model loaded successfully.") | |
| except Exception as e: | |
| print(f"β Model loading failed: {e}") | |
| sys.exit(1) | |
| # ----------------- Load Codec ----------------- | |
| print("π§ Loading codec model...") | |
| basic_model_config = './xcodec_mini_infer/final_ckpt/config.yaml' | |
| resume_path = './xcodec_mini_infer/final_ckpt/ckpt_00100000.pth' | |
| mmtokenizer = _MMSentencePieceTokenizer("./mm_tokenizer_v0.2_hf/tokenizer.model") | |
| codectool = CodecManipulator("xcodec", 0, 1) | |
| model_config = OmegaConf.load(basic_model_config) | |
| codec_model = eval(model_config.generator.name)(**model_config.generator.config).to(device) | |
| state_dict = torch.load(resume_path, map_location="cpu") | |
| codec_model.load_state_dict(state_dict['codec_model']) | |
| codec_model.eval() | |
| print("β Codec model loaded successfully.") | |
| # ---------------- Utility ----------------- | |
| class BlockTokenRangeProcessor(LogitsProcessor): | |
| def __init__(self, start_id, end_id): | |
| self.blocked_token_ids = list(range(start_id, end_id)) | |
| def __call__(self, input_ids, scores): | |
| scores[:, self.blocked_token_ids] = -float("inf") | |
| return scores | |
| def split_lyrics(lyrics: str): | |
| pattern = r"\[(\w+)\]\s*(.*?)(?=\s*\n\[|\Z)" | |
| segments = re.findall(pattern, lyrics, re.DOTALL) | |
| return [f"[{seg[0]}]\n{seg[1].strip()}\n\n" for seg in segments] | |
| def save_audio(wav: torch.Tensor, path, sample_rate: int, rescale: bool = False): | |
| limit = 0.99 | |
| max_val = wav.abs().max() | |
| wav = wav * min(limit / max_val, 1) if rescale else wav.clamp(-limit, limit) | |
| torchaudio.save(str(path), wav, sample_rate=sample_rate, encoding='PCM_S', bits_per_sample=16) | |
| # ---------------- Generation ----------------- | |
| def generate_music(genre_txt, lyrics_txt, progress=gr.Progress()): | |
| with tempfile.TemporaryDirectory() as output_dir: | |
| genres = genre_txt.strip() | |
| lyrics = split_lyrics(lyrics_txt + "\n") | |
| prompt_texts = [f"Generate music from lyrics.\n[Genre] {genres}\n" + "\n".join(lyrics)] | |
| random_id = uuid.uuid4() | |
| print("πΆ Generating music...") | |
| start_of_segment = mmtokenizer.tokenize('[start_of_segment]') | |
| end_of_segment = mmtokenizer.tokenize('[end_of_segment]') | |
| head_id = mmtokenizer.tokenize(prompt_texts[0]) | |
| prompt_ids = torch.as_tensor(head_id + start_of_segment + [mmtokenizer.soa]).unsqueeze(0).to(device) | |
| with torch.inference_mode(): | |
| output_seq = model.generate( | |
| input_ids=prompt_ids, | |
| max_new_tokens=32, | |
| top_p=0.9, | |
| temperature=0.8, | |
| repetition_penalty=1.1, | |
| eos_token_id=mmtokenizer.eoa, | |
| pad_token_id=mmtokenizer.eoa, | |
| logits_processor=LogitsProcessorList([BlockTokenRangeProcessor(0, 32002)]), | |
| ) | |
| ids = output_seq[0].cpu().numpy() | |
| soa_idx = np.where(ids == mmtokenizer.soa)[0].tolist() | |
| eoa_idx = np.where(ids == mmtokenizer.eoa)[0].tolist() | |
| vocals, instr = [], [] | |
| for i in range(len(soa_idx)): | |
| codec_ids = ids[soa_idx[i] + 1:eoa_idx[i]] | |
| codec_ids = codec_ids[:2 * (len(codec_ids) // 2)] | |
| v = codectool.ids2npy(rearrange(codec_ids, "(n b) -> b n", b=2)[0]) | |
| vocals.append(v) | |
| ins = codectool.ids2npy(rearrange(codec_ids, "(n b) -> b n", b=2)[1]) | |
| instr.append(ins) | |
| vocals = np.concatenate(vocals, axis=1) | |
| instr = np.concatenate(instr, axis=1) | |
| mix = (vocals + instr) / 2 | |
| recons_dir = os.path.join(output_dir, "recons") | |
| os.makedirs(recons_dir, exist_ok=True) | |
| mix_path = os.path.join(recons_dir, f"mix_{random_id}.wav") | |
| save_audio(torch.tensor(mix).unsqueeze(0), mix_path, 16000) | |
| gc.collect() | |
| print("β Generation complete.") | |
| return mix_path | |
| # ---------------- Gradio Interface ----------------- | |
| with gr.Blocks() as demo: | |
| gr.Markdown("# π΅ YuE CPU Music Generator (Low-Memory Edition)") | |
| genre_txt = gr.Textbox(label="Genre", placeholder="Pop, Jazz, Hip-Hop...") | |
| lyrics_txt = gr.Textbox(label="Lyrics", placeholder="[Verse]\nI walk the night...") | |
| music_out = gr.Audio(label="Generated Song") | |
| btn = gr.Button("Generate πΆ") | |
| btn.click(generate_music, inputs=[genre_txt, lyrics_txt], outputs=[music_out]) | |
| demo.queue().launch(show_error=True, share=True) | |