Files
fspecii 565faacb7b Gradio API migration, training pipeline, news page, and UI improvements
- Migrate backend from REST API to Gradio @gradio/client for generation
- Fix Gradio parameter alignment (positions 36-49) for reference/cover audio
- Add LoRA training pipeline with dataset upload, preprocessing, and export
- Add News page with dismiss/restore and GitHub star button
- Add localization info icon in Settings language section
- Fix upload audio URL prefix, add missing MIME types
- Add training API routes and Python preprocess script
- Update i18n with news keys for all languages
2026-02-09 22:30:15 +02:00

141 lines
5.1 KiB
Python

"""
Standalone dataset preprocessor for ACE-Step LoRA training.
Converts labeled audio samples from a dataset JSON into pre-computed
tensor files (.pt) suitable for training. This script loads the VAE and
text encoder independently, so it does NOT require the Gradio app to be
running.
Usage:
python preprocess_dataset.py --dataset /path/to/dataset.json --output /path/to/tensors [--json]
The --json flag makes the script output a final JSON summary line to stdout.
"""
import argparse
import json
import os
import sys
def main():
parser = argparse.ArgumentParser(description="Preprocess dataset to tensors for LoRA training")
parser.add_argument("--dataset", required=True, help="Path to dataset JSON file")
parser.add_argument("--output", required=True, help="Output directory for tensor files")
parser.add_argument("--max-duration", type=float, default=240.0, help="Max audio duration in seconds")
parser.add_argument("--json", action="store_true", help="Output JSON summary")
args = parser.parse_args()
if not os.path.exists(args.dataset):
print(f"Error: Dataset file not found: {args.dataset}", file=sys.stderr)
sys.exit(1)
# Add ACE-Step root to path for imports
ace_step_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
# Walk up to find ACE-Step-1.5 directory
for candidate in [
os.path.join(ace_step_root, "ACE-Step-1.5"),
os.path.join(os.path.dirname(ace_step_root), "ACE-Step-1.5"),
os.getcwd(),
]:
if os.path.isdir(candidate) and os.path.isdir(os.path.join(candidate, "acestep")):
ace_step_root = candidate
break
if ace_step_root not in sys.path:
sys.path.insert(0, ace_step_root)
try:
from acestep.training.dataset_builder import DatasetBuilder
except ImportError as e:
print(f"Error: Could not import ACE-Step modules: {e}", file=sys.stderr)
print("Make sure this script is run from the ACE-Step-1.5 directory or with the correct Python environment.", file=sys.stderr)
sys.exit(1)
# Load dataset JSON
print(f"Loading dataset: {args.dataset}")
with open(args.dataset, "r") as f:
dataset_data = json.load(f)
# Reconstruct DatasetBuilder from JSON
builder = DatasetBuilder()
builder.load_from_dict(dataset_data)
labeled_count = sum(1 for s in builder.samples if s.labeled)
total_count = len(builder.samples)
print(f"Dataset loaded: {total_count} samples, {labeled_count} labeled")
if labeled_count == 0:
msg = "No labeled samples found. Please label samples before preprocessing."
print(f"Warning: {msg}", file=sys.stderr)
if args.json:
print(json.dumps({"status": "error", "message": msg, "labeled": 0, "total": total_count}))
sys.exit(1)
# Load models for preprocessing
print("Loading models for preprocessing (this may take a moment)...")
try:
from acestep.pipeline_ace_step import ACEStepPipeline
checkpoint_dir = os.path.join(ace_step_root, "checkpoints")
if not os.path.isdir(checkpoint_dir):
checkpoint_dir = os.path.join(ace_step_root, "checkpoints", "ACE-Step-v1.5")
pipe = ACEStepPipeline(checkpoint_dir=checkpoint_dir)
pipe.load_checkpoint()
# Create a minimal dit_handler-like object for preprocess_to_tensors
class DitHandlerProxy:
def __init__(self, pipeline):
self.model = pipeline.dit
self.vae = pipeline.vae
self.text_encoder = pipeline.text_encoder
self.text_tokenizer = pipeline.text_tokenizer
self.silence_latent = getattr(pipeline, "silence_latent", None)
self.device = pipeline.device
self.dtype = pipeline.dtype
handler = DitHandlerProxy(pipe)
except Exception as e:
# If pipeline loading fails, try a simpler approach
print(f"Warning: Could not load full pipeline: {e}", file=sys.stderr)
print("Preprocessing requires model access. Please use the Gradio UI for preprocessing.", file=sys.stderr)
if args.json:
print(json.dumps({
"status": "error",
"message": f"Model loading failed: {str(e)}. Use Gradio UI preprocess instead.",
"labeled": labeled_count,
"total": total_count,
}))
sys.exit(1)
# Run preprocessing
os.makedirs(args.output, exist_ok=True)
print(f"Preprocessing to: {args.output}")
def progress_cb(msg):
print(f" {msg}")
output_paths, status = builder.preprocess_to_tensors(
dit_handler=handler,
output_dir=args.output,
max_duration=args.max_duration,
progress_callback=progress_cb,
)
print(f"Done: {status}")
print(f"Output files: {len(output_paths)}")
if args.json:
print(json.dumps({
"status": "complete",
"message": status,
"output_files": len(output_paths),
"output_dir": args.output,
"labeled": labeled_count,
"total": total_count,
}))
if __name__ == "__main__":
main()