import os import tempfile import time import ffmpeg import modal import numpy as np from suno_utils.tasks.gpt.generation import * from suno_utils.tasks.gpt_v2 import chirp_v1 from suno_utils.worker.loader import S3Loader from suno_utils.worker.modal_base import MODAL_MOUNTS, get_modal_base_image from suno_utils.worker.schema import QueueItem from suno_utils.worker.utils import download_models_to_dir CHIRP_V1_MODELS = dict( codec_path="georg/trained_models/chirp_v1/codec.pt", ) MOUNT_PATH = "/suno/models" class ConcatWorker(S3Loader): def __init__(self, bg_image=None): super().__init__(bg_image=bg_image) self.bg_image = bg_image def preload(self): start_time = time.time() chirp_v1.preload_codec_models( f"{MOUNT_PATH}/{CHIRP_V1_MODELS['codec_path']}", ) finish_time = time.time() print(f"Preloading took {finish_time - start_time}s") @staticmethod def download_models(dir_path=MOUNT_PATH): """Use AWS CLI to download models if they don't exist.""" files = list(CHIRP_V1_MODELS.values()) download_models_to_dir(files, dir_path) def concat_videos(self, new_id: str, ids: list[str]): from suno_utils.worker.settings import s3_client print(ids) filenames = [f"{id}.mp4" for id in ids] with tempfile.TemporaryDirectory() as td: full_paths = [] for fname in filenames: full_path = os.path.join(td, fname) full_paths.append(full_path) with open(full_path, "wb") as tmp_file: s3_client.download_fileobj( "suno-data-uploads", f"studio/uploads/{fname}", tmp_file, ) with open(full_path.replace(".mp4", ".npz"), "wb") as tmp_file: s3_client.download_fileobj( "suno-data-uploads", f"studio/uploads/{fname.replace('.mp4', '.npz')}", tmp_file, ) npzs = [np.load(p.replace(".mp4", ".npz")) for p in full_paths] audio = chirp_v1.codec_decode( np.concatenate([n["v1_raw"] if "v1_raw" in n else n["v1.0_raw"] for n in npzs], axis=0)[ ::3, -8: ] ) # we keep wav operation here for high resolution, but we don't actually save these wavs full_audio_path = os.path.join(td, "concat.wav") audio.write_wav(full_audio_path) inputs = [(ffmpeg.input(p), ffmpeg.input(p.replace(".mp4", ".wav"))) for p in full_paths] full_path = os.path.join(td, "concat.mp4") joined = ffmpeg.concat(*[x for i in inputs for x in (i[0]["v"],)], v=1, a=0) ffmpeg.output(joined, full_path).run() full_path_2 = os.path.join(td, "concat_2.mp4") ffmpeg.concat(ffmpeg.input(full_path), ffmpeg.input(full_audio_path), v=1, a=1).output( full_path_2 ).run() s3_client.upload_file(full_path_2, "suno-data-uploads", f"studio/uploads/{new_id}.mp4") def download_model_wrapper_5(): ConcatWorker.download_models() image = get_modal_base_image().run_function( download_model_wrapper_5, secret=modal.Secret.from_name("studio-aws") ) STUB_NAME = "concat-v0-alpha" stub = modal.Stub(STUB_NAME, image=image) @stub.cls( cpu=2.0, gpu="any", secrets=[ modal.Secret.from_name("studio-aws"), modal.Secret.from_dict({"SUNO_ASSETS_PATH": "/suno/models/assets"}), ], timeout=60, container_idle_timeout=60, mounts=MODAL_MOUNTS, concurrency_limit=8, ) class ConcatStub: def __enter__(self): self.worker = ConcatWorker(bg_image="/suno/models/assets/wave-bg-3.png") self.worker.preload() @modal.method() def concat_videos(self, new_id: str, ids: list[str], callback_url: str | None = None): self.worker.concat_videos( new_id, ids, ) if callback_url: self.worker.notify_finish( QueueItem(id=new_id, metadata={}, callback_url=callback_url), { "id": new_id, "type": "concat_videos", }, ) @stub.local_entrypoint() def main(): import uuid new_id = str(uuid.uuid4()) print(new_id) model = ConcatStub() model.concat_videos.remote( new_id, [ "7d3dba59-2ab5-4d2d-9d05-69b298820edf_1", "162b5c15-4e56-4d49-8402-1a48c5b231af_1", ], )