Initial commit: ACE-Step UI - Open source music generation interface
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Format lyrics and style using the 5Hz LLM.
|
||||
|
||||
This script uses ACE-Step's format_sample to enhance user input with AI-generated
|
||||
music metadata (BPM, duration, key, time signature, enhanced description).
|
||||
"""
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
# Get ACE-Step path from environment or use default
|
||||
ACESTEP_PATH = os.environ.get('ACESTEP_PATH', '/home/ambsd/Desktop/aceui/ACE-Step-1.5')
|
||||
sys.path.insert(0, ACESTEP_PATH)
|
||||
|
||||
from acestep.llm_inference import LLMHandler
|
||||
from acestep.inference import format_sample
|
||||
|
||||
# Global handler
|
||||
_llm_handler = None
|
||||
|
||||
def get_llm_handler():
|
||||
global _llm_handler
|
||||
if _llm_handler is None:
|
||||
_llm_handler = LLMHandler()
|
||||
# Initialize the LLM with the 0.6B model (lighter on VRAM)
|
||||
checkpoint_dir = os.path.join(ACESTEP_PATH, "checkpoints")
|
||||
lm_model_path = "acestep-5Hz-lm-0.6B" # Use the smaller 0.6B model
|
||||
|
||||
status, success = _llm_handler.initialize(
|
||||
checkpoint_dir=checkpoint_dir,
|
||||
lm_model_path=lm_model_path,
|
||||
backend="pt", # Use PyTorch backend
|
||||
device="cuda",
|
||||
offload_to_cpu=True,
|
||||
)
|
||||
|
||||
if not success:
|
||||
raise RuntimeError(f"Failed to initialize LLM: {status}")
|
||||
|
||||
return _llm_handler
|
||||
|
||||
def format_input(
|
||||
caption: str,
|
||||
lyrics: str = "",
|
||||
bpm: int = 0,
|
||||
duration: int = 0,
|
||||
key_scale: str = "",
|
||||
time_signature: str = "",
|
||||
temperature: float = 0.85,
|
||||
top_k: int = 0,
|
||||
top_p: float = 0.9,
|
||||
):
|
||||
"""Format caption and lyrics using the LLM."""
|
||||
handler = get_llm_handler()
|
||||
|
||||
# Build user metadata for constrained decoding
|
||||
user_metadata = {}
|
||||
if bpm and bpm > 0:
|
||||
user_metadata['bpm'] = int(bpm)
|
||||
if duration and duration > 0:
|
||||
user_metadata['duration'] = int(duration)
|
||||
if key_scale and key_scale.strip():
|
||||
user_metadata['keyscale'] = key_scale.strip()
|
||||
if time_signature and time_signature.strip():
|
||||
user_metadata['timesignature'] = time_signature.strip()
|
||||
|
||||
user_metadata_to_pass = user_metadata if user_metadata else None
|
||||
top_k_value = None if not top_k or top_k == 0 else int(top_k)
|
||||
top_p_value = None if not top_p or top_p >= 1.0 else top_p
|
||||
|
||||
result = format_sample(
|
||||
llm_handler=handler,
|
||||
caption=caption,
|
||||
lyrics=lyrics,
|
||||
user_metadata=user_metadata_to_pass,
|
||||
temperature=temperature,
|
||||
top_k=top_k_value,
|
||||
top_p=top_p_value,
|
||||
use_constrained_decoding=True,
|
||||
)
|
||||
|
||||
return {
|
||||
"success": result.success,
|
||||
"caption": result.caption,
|
||||
"lyrics": result.lyrics,
|
||||
"bpm": result.bpm,
|
||||
"duration": result.duration,
|
||||
"key_scale": result.keyscale,
|
||||
"language": result.language,
|
||||
"time_signature": result.timesignature,
|
||||
"status_message": result.status_message,
|
||||
}
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Format lyrics and style using ACE-Step LLM")
|
||||
parser.add_argument("--caption", type=str, required=True, help="Style/caption description")
|
||||
parser.add_argument("--lyrics", type=str, default="", help="Lyrics text")
|
||||
parser.add_argument("--bpm", type=int, default=0, help="Optional BPM constraint")
|
||||
parser.add_argument("--duration", type=int, default=0, help="Optional duration constraint")
|
||||
parser.add_argument("--key-scale", type=str, default="", help="Optional key scale constraint")
|
||||
parser.add_argument("--time-signature", type=str, default="", help="Optional time signature constraint")
|
||||
parser.add_argument("--temperature", type=float, default=0.85, help="LLM temperature")
|
||||
parser.add_argument("--top-k", type=int, default=0, help="LLM top-k sampling")
|
||||
parser.add_argument("--top-p", type=float, default=0.9, help="LLM top-p sampling")
|
||||
parser.add_argument("--json", action="store_true", help="Output as JSON")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
start_time = time.time()
|
||||
result = format_input(
|
||||
caption=args.caption,
|
||||
lyrics=args.lyrics,
|
||||
bpm=args.bpm,
|
||||
duration=args.duration,
|
||||
key_scale=args.key_scale,
|
||||
time_signature=args.time_signature,
|
||||
temperature=args.temperature,
|
||||
top_k=args.top_k,
|
||||
top_p=args.top_p,
|
||||
)
|
||||
elapsed = time.time() - start_time
|
||||
result["elapsed_seconds"] = elapsed
|
||||
|
||||
if args.json:
|
||||
print(json.dumps(result))
|
||||
else:
|
||||
if result["success"]:
|
||||
print(f"Caption: {result['caption']}")
|
||||
print(f"Lyrics: {result['lyrics'][:100]}...")
|
||||
print(f"BPM: {result['bpm']}")
|
||||
print(f"Duration: {result['duration']}")
|
||||
print(f"Key: {result['key_scale']}")
|
||||
print(f"Time Signature: {result['time_signature']}")
|
||||
print(f"Language: {result['language']}")
|
||||
else:
|
||||
print(f"Error: {result['status_message']}")
|
||||
|
||||
except Exception as e:
|
||||
if args.json:
|
||||
print(json.dumps({"success": False, "error": str(e)}))
|
||||
else:
|
||||
print(f"Error: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,284 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Simple music generation script that works like the Gradio interface.
|
||||
|
||||
This is a wrapper script that calls ACE-Step without modifying the original repo.
|
||||
Supports all ACE-Step generation parameters.
|
||||
"""
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
# Get ACE-Step path from environment or use default
|
||||
ACESTEP_PATH = os.environ.get('ACESTEP_PATH', '/home/ambsd/Desktop/aceui/ACE-Step-1.5')
|
||||
|
||||
# Add ACE-Step to path
|
||||
sys.path.insert(0, ACESTEP_PATH)
|
||||
|
||||
from acestep.handler import AceStepHandler
|
||||
from acestep.llm_inference import LLMHandler
|
||||
from acestep.inference import GenerationParams, GenerationConfig, generate_music
|
||||
|
||||
# Global handlers (initialized once)
|
||||
_handler = None
|
||||
_llm_handler = None
|
||||
|
||||
def get_handlers():
|
||||
global _handler, _llm_handler
|
||||
if _handler is None:
|
||||
_handler = AceStepHandler()
|
||||
_handler.initialize_service(
|
||||
project_root=ACESTEP_PATH,
|
||||
config_path="acestep-v15-turbo",
|
||||
device="cuda",
|
||||
offload_to_cpu=True, # For 12GB GPU
|
||||
)
|
||||
_llm_handler = LLMHandler() # Create but don't initialize (not enough VRAM)
|
||||
return _handler, _llm_handler
|
||||
|
||||
def generate(
|
||||
# Basic parameters
|
||||
prompt: str,
|
||||
lyrics: str = "",
|
||||
instrumental: bool = False,
|
||||
duration: int = 60,
|
||||
bpm: int = 0,
|
||||
key_scale: str = "",
|
||||
time_signature: str = "",
|
||||
vocal_language: str = "auto",
|
||||
|
||||
# Generation parameters
|
||||
infer_steps: int = 8,
|
||||
guidance_scale: float = 10.0,
|
||||
batch_size: int = 1,
|
||||
seed: int = -1,
|
||||
audio_format: str = "mp3",
|
||||
shift: float = 3.0,
|
||||
|
||||
# Task type parameters
|
||||
task_type: str = "text2music",
|
||||
reference_audio: str = None,
|
||||
src_audio: str = None,
|
||||
audio_codes: str = "",
|
||||
repainting_start: float = 0,
|
||||
repainting_end: float = -1,
|
||||
audio_cover_strength: float = 1.0,
|
||||
instruction: str = "",
|
||||
|
||||
# LM/CoT parameters
|
||||
thinking: bool = False,
|
||||
lm_temperature: float = 0.85,
|
||||
lm_cfg_scale: float = 2.0,
|
||||
lm_top_k: int = 0,
|
||||
lm_top_p: float = 0.9,
|
||||
lm_negative_prompt: str = "",
|
||||
use_cot_metas: bool = True,
|
||||
use_cot_caption: bool = True,
|
||||
use_cot_language: bool = True,
|
||||
|
||||
# Advanced parameters
|
||||
use_adg: bool = False,
|
||||
cfg_interval_start: float = 0.0,
|
||||
cfg_interval_end: float = 1.0,
|
||||
|
||||
# Output
|
||||
output_dir: str = None,
|
||||
):
|
||||
"""Generate music and return audio file paths."""
|
||||
handler, llm_handler = get_handlers()
|
||||
|
||||
if output_dir is None:
|
||||
output_dir = os.path.join(ACESTEP_PATH, "output")
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
|
||||
# Build generation params
|
||||
params = GenerationParams(
|
||||
# Basic
|
||||
task_type=task_type,
|
||||
caption=prompt,
|
||||
lyrics=lyrics if lyrics and not instrumental else "",
|
||||
instrumental=instrumental,
|
||||
duration=float(duration) if duration > 0 else -1.0,
|
||||
bpm=bpm if bpm > 0 else None,
|
||||
keyscale=key_scale if key_scale else "",
|
||||
timesignature=time_signature if time_signature else "",
|
||||
vocal_language=vocal_language if vocal_language else "auto",
|
||||
|
||||
# Generation
|
||||
inference_steps=infer_steps,
|
||||
guidance_scale=guidance_scale,
|
||||
seed=seed if seed >= 0 else -1,
|
||||
shift=shift,
|
||||
|
||||
# Task-specific
|
||||
reference_audio=reference_audio if reference_audio else None,
|
||||
src_audio=src_audio if src_audio else None,
|
||||
audio_codes=audio_codes if audio_codes else "",
|
||||
repainting_start=repainting_start,
|
||||
repainting_end=repainting_end,
|
||||
audio_cover_strength=audio_cover_strength,
|
||||
instruction=instruction if instruction else "Fill the audio semantic mask based on the given conditions:",
|
||||
|
||||
# LM/CoT
|
||||
thinking=thinking,
|
||||
lm_temperature=lm_temperature,
|
||||
lm_cfg_scale=lm_cfg_scale,
|
||||
lm_top_k=lm_top_k,
|
||||
lm_top_p=lm_top_p,
|
||||
lm_negative_prompt=lm_negative_prompt if lm_negative_prompt else "NO USER INPUT",
|
||||
use_cot_metas=use_cot_metas,
|
||||
use_cot_caption=use_cot_caption,
|
||||
use_cot_language=use_cot_language,
|
||||
|
||||
# Advanced
|
||||
use_adg=use_adg,
|
||||
cfg_interval_start=cfg_interval_start,
|
||||
cfg_interval_end=cfg_interval_end,
|
||||
)
|
||||
|
||||
# Build generation config
|
||||
config = GenerationConfig(
|
||||
batch_size=batch_size,
|
||||
audio_format=audio_format,
|
||||
use_random_seed=(seed < 0),
|
||||
)
|
||||
|
||||
start_time = time.time()
|
||||
result = generate_music(handler, llm_handler, params, config, save_dir=output_dir)
|
||||
elapsed = time.time() - start_time
|
||||
|
||||
# Extract audio paths from result
|
||||
audio_paths = []
|
||||
if result.audios:
|
||||
for audio in result.audios:
|
||||
if isinstance(audio, dict) and audio.get("path"):
|
||||
audio_paths.append(audio["path"])
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"audio_paths": audio_paths,
|
||||
"elapsed_seconds": elapsed,
|
||||
"output_dir": output_dir,
|
||||
}
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Generate music with ACE-Step")
|
||||
|
||||
# Basic parameters
|
||||
parser.add_argument("--prompt", type=str, required=True, help="Music description")
|
||||
parser.add_argument("--lyrics", type=str, default="", help="Lyrics (optional)")
|
||||
parser.add_argument("--instrumental", action="store_true", help="Generate instrumental music")
|
||||
parser.add_argument("--duration", type=int, default=60, help="Duration in seconds (0 for auto)")
|
||||
parser.add_argument("--bpm", type=int, default=0, help="BPM (0 for auto)")
|
||||
parser.add_argument("--key-scale", type=str, default="", help="Key scale (e.g., 'C Major')")
|
||||
parser.add_argument("--time-signature", type=str, default="", help="Time signature (2, 3, 4, or 6)")
|
||||
parser.add_argument("--vocal-language", type=str, default="auto", help="Vocal language code")
|
||||
|
||||
# Generation parameters
|
||||
parser.add_argument("--infer-steps", type=int, default=8, help="Inference steps")
|
||||
parser.add_argument("--guidance-scale", type=float, default=10.0, help="Guidance scale")
|
||||
parser.add_argument("--batch-size", type=int, default=1, help="Batch size")
|
||||
parser.add_argument("--seed", type=int, default=-1, help="Random seed (-1 for random)")
|
||||
parser.add_argument("--audio-format", type=str, default="mp3", choices=["mp3", "flac", "wav"])
|
||||
parser.add_argument("--shift", type=float, default=3.0, help="Timestep shift factor")
|
||||
|
||||
# Task type parameters
|
||||
parser.add_argument("--task-type", type=str, default="text2music",
|
||||
choices=["text2music", "cover", "repaint", "lego", "extract", "complete"],
|
||||
help="Generation task type")
|
||||
parser.add_argument("--reference-audio", type=str, default=None, help="Reference audio path for style transfer")
|
||||
parser.add_argument("--src-audio", type=str, default=None, help="Source audio path for audio-to-audio")
|
||||
parser.add_argument("--audio-codes", type=str, default="", help="Audio semantic codes")
|
||||
parser.add_argument("--repainting-start", type=float, default=0, help="Repainting start time (seconds)")
|
||||
parser.add_argument("--repainting-end", type=float, default=-1, help="Repainting end time (seconds)")
|
||||
parser.add_argument("--audio-cover-strength", type=float, default=1.0, help="Reference audio strength (0-1)")
|
||||
parser.add_argument("--instruction", type=str, default="", help="Task instruction prompt")
|
||||
|
||||
# LM/CoT parameters
|
||||
parser.add_argument("--thinking", action="store_true", help="Enable Chain-of-Thought reasoning")
|
||||
parser.add_argument("--lm-temperature", type=float, default=0.85, help="LLM temperature")
|
||||
parser.add_argument("--lm-cfg-scale", type=float, default=2.0, help="LLM guidance scale")
|
||||
parser.add_argument("--lm-top-k", type=int, default=0, help="LLM top-k sampling")
|
||||
parser.add_argument("--lm-top-p", type=float, default=0.9, help="LLM top-p sampling")
|
||||
parser.add_argument("--lm-negative-prompt", type=str, default="", help="LLM negative prompt")
|
||||
parser.add_argument("--no-cot-metas", action="store_true", help="Disable CoT for metadata")
|
||||
parser.add_argument("--no-cot-caption", action="store_true", help="Disable CoT for caption")
|
||||
parser.add_argument("--no-cot-language", action="store_true", help="Disable CoT for language")
|
||||
|
||||
# Advanced parameters
|
||||
parser.add_argument("--use-adg", action="store_true", help="Use Adaptive Dual Guidance")
|
||||
parser.add_argument("--cfg-interval-start", type=float, default=0.0, help="CFG interval start")
|
||||
parser.add_argument("--cfg-interval-end", type=float, default=1.0, help="CFG interval end")
|
||||
|
||||
# Output
|
||||
parser.add_argument("--output-dir", type=str, default=None, help="Output directory")
|
||||
parser.add_argument("--json", action="store_true", help="Output as JSON")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
try:
|
||||
result = generate(
|
||||
# Basic
|
||||
prompt=args.prompt,
|
||||
lyrics=args.lyrics,
|
||||
instrumental=args.instrumental,
|
||||
duration=args.duration,
|
||||
bpm=args.bpm,
|
||||
key_scale=args.key_scale,
|
||||
time_signature=args.time_signature,
|
||||
vocal_language=args.vocal_language,
|
||||
|
||||
# Generation
|
||||
infer_steps=args.infer_steps,
|
||||
guidance_scale=args.guidance_scale,
|
||||
batch_size=args.batch_size,
|
||||
seed=args.seed,
|
||||
audio_format=args.audio_format,
|
||||
shift=args.shift,
|
||||
|
||||
# Task type
|
||||
task_type=args.task_type,
|
||||
reference_audio=args.reference_audio,
|
||||
src_audio=args.src_audio,
|
||||
audio_codes=args.audio_codes,
|
||||
repainting_start=args.repainting_start,
|
||||
repainting_end=args.repainting_end,
|
||||
audio_cover_strength=args.audio_cover_strength,
|
||||
instruction=args.instruction,
|
||||
|
||||
# LM/CoT
|
||||
thinking=args.thinking,
|
||||
lm_temperature=args.lm_temperature,
|
||||
lm_cfg_scale=args.lm_cfg_scale,
|
||||
lm_top_k=args.lm_top_k,
|
||||
lm_top_p=args.lm_top_p,
|
||||
lm_negative_prompt=args.lm_negative_prompt,
|
||||
use_cot_metas=not args.no_cot_metas,
|
||||
use_cot_caption=not args.no_cot_caption,
|
||||
use_cot_language=not args.no_cot_language,
|
||||
|
||||
# Advanced
|
||||
use_adg=args.use_adg,
|
||||
cfg_interval_start=args.cfg_interval_start,
|
||||
cfg_interval_end=args.cfg_interval_end,
|
||||
|
||||
# Output
|
||||
output_dir=args.output_dir,
|
||||
)
|
||||
|
||||
if args.json:
|
||||
print(json.dumps(result))
|
||||
else:
|
||||
print(f"Generated {len(result['audio_paths'])} audio files in {result['elapsed_seconds']:.1f}s:")
|
||||
for path in result['audio_paths']:
|
||||
print(f" {path}")
|
||||
except Exception as e:
|
||||
if args.json:
|
||||
print(json.dumps({"success": False, "error": str(e)}))
|
||||
else:
|
||||
print(f"Error: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user