$ cat node-template.py
Music Creation
// Generates a music track from a style description and lyrics using ACE-Step 1.5 via a native GPU service. Supports configurable BPM, musical key, time signature, duration (10-300s), and lyrics language. Outputs an MP3 audio file.
Process
Audio
template.py
1import os2import sys3import json4import subprocess5import time6import traceback78try:9 import requests10except ImportError:11 subprocess.check_call([sys.executable, "-m", "pip", "install", "requests"])12 import requests1314NATIVE_MUSIC_CREATION_SERVICE_URL = os.getenv(15 "NATIVE_MUSIC_CREATION_SERVICE_URL", "http://native-music-creation-service:8110"16)17_EMBLEMA_VERSION = os.getenv("EMBLEMA_VERSION", "dev")18NATIVE_MUSIC_CREATION_SERVICE_IMAGE = os.getenv(19 "NATIVE_MUSIC_CREATION_SERVICE_IMAGE",20 f"emblema/native-music-creation-service:{_EMBLEMA_VERSION}",21)22HF_CACHE_HOST_PATH = os.getenv("HF_CACHE_HOST_PATH", "/root/.cache/huggingface")23CONTAINER_NAME = "native-music-creation-service"24OUTPUT_DIR = "/data/output"252627def start_container():28 """Create and start native-music-creation-service, removing any stale container first."""29 subprocess.run(30 ["docker", "rm", "-f", CONTAINER_NAME],31 capture_output=True, text=True32 )3334 hf_token = os.getenv("HUGGINGFACE_TOKEN", "")35 print(f"Creating container {CONTAINER_NAME}...", file=sys.stderr)36 run_cmd = [37 "docker", "run", "-d",38 "--name", CONTAINER_NAME,39 "--network", "emblema",40 "--gpus", "all",41 "-e", "PORT=8110",42 "-e", "DEVICE=cuda",43 "-e", f"HF_TOKEN={hf_token}",44 "-v", f"{HF_CACHE_HOST_PATH}:/root/.cache/huggingface",45 NATIVE_MUSIC_CREATION_SERVICE_IMAGE,46 ]47 result = subprocess.run(run_cmd, capture_output=True, text=True)48 if result.returncode != 0:49 print(f"docker run failed (exit {result.returncode}): {result.stderr}", file=sys.stderr)50 raise RuntimeError(f"Failed to start container: {result.stderr}")5152 # Poll health endpoint53 timeout = 18054 interval = 355 elapsed = 056 health_url = f"{NATIVE_MUSIC_CREATION_SERVICE_URL}/health"57 while elapsed < timeout:58 try:59 r = requests.get(health_url, timeout=5)60 if r.status_code == 200:61 print(f"Container healthy (waited {elapsed}s).", file=sys.stderr)62 return63 except requests.ConnectionError:64 pass65 time.sleep(interval)66 elapsed += interval6768 raise RuntimeError(f"Container did not become healthy within {timeout}s")697071def stop_container():72 """Remove the container."""73 try:74 subprocess.run(75 ["docker", "rm", "-f", CONTAINER_NAME],76 capture_output=True, text=True, timeout=3077 )78 print(f"Container {CONTAINER_NAME} removed.", file=sys.stderr)79 except Exception as e:80 print(f"Warning: failed to remove container: {e}", file=sys.stderr)818283def main():84 try:85 input_json = sys.stdin.read()86 execution_input = json.loads(input_json)87 inputs = execution_input.get("inputs", {})8889 prompt = inputs.get("prompt", "")90 lyrics = inputs.get("lyrics", "")91 duration = int(inputs.get("duration", 90))92 language = inputs.get("language", "en")93 time_signature = inputs.get("time_signature", "4")94 bpm = int(inputs.get("bpm", 190))95 keyscale = inputs.get("keyscale", "E minor")9697 if not prompt:98 raise ValueError("Prompt input is required")99 if not lyrics:100 raise ValueError("Lyrics input is required")101 if not (10 <= duration <= 300):102 raise ValueError(f"Duration must be between 10 and 300, got {duration}")103 if not (40 <= bpm <= 300):104 raise ValueError(f"BPM must be between 40 and 300, got {bpm}")105106 os.makedirs(OUTPUT_DIR, exist_ok=True)107108 # Start the container109 start_container()110111 try:112 # JSON POST (no file inputs)113 payload = {114 "prompt": prompt,115 "lyrics": lyrics,116 "duration": duration,117 "language": language,118 "time_signature": time_signature,119 "bpm": bpm,120 "keyscale": keyscale,121 }122123 resp = requests.post(124 f"{NATIVE_MUSIC_CREATION_SERVICE_URL}/generate",125 json=payload,126 timeout=600,127 )128129 if resp.status_code != 200:130 try:131 error_detail = resp.json()132 except Exception:133 error_detail = resp.text134 raise RuntimeError(135 f"Music creation service returned {resp.status_code}: {error_detail}"136 )137138 # Save result139 out_filename = "generated_music.mp3"140 out_path = os.path.join(OUTPUT_DIR, out_filename)141 with open(out_path, "wb") as f:142 f.write(resp.content)143144 inference_time = resp.headers.get("X-Inference-Time-Ms", "unknown")145 print(146 f"Music generated: time={inference_time}ms, duration={duration}s, "147 f"bpm={bpm}, key={keyscale}, time_sig={time_signature}, language={language}",148 file=sys.stderr,149 )150151 # Flat output -- keys match OUTPUT_SCHEMA152 output = {153 "audio": out_filename,154 }155 print(json.dumps(output, indent=2))156157 finally:158 stop_container()159160 except Exception as e:161 error_output = {162 "error": str(e),163 "errorType": type(e).__name__,164 "traceback": traceback.format_exc(),165 }166 print(json.dumps(error_output), file=sys.stderr)167 sys.exit(1)168169170if __name__ == "__main__":171 main()