Compare commits

..
4 Commits
Author SHA1 Message Date
Leonid PershinandClaude Opus 5 7f441defcc feat: add start.sh for Linux/macOS, harden both launchers
start.sh mirrors start.bat: finds Python 3.10+, creates the venv,
installs PyTorch (CUDA index on Linux, the MPS build on macOS, or the CPU
index with --cpu), installs ACE-Step, reports the device and launches the
UI. Same flags, and the defaults can also come from the environment
(PORT=7870 ./start.sh). On macOS it passes --bf16 false, which the README
already calls for. Dropped start.sh from .gitignore, where it sat among
the upstream author's local scratch files.

Both launchers also gain two fixes found while testing on WSL:

- A venv is only accepted if pip works in it, not merely if the
  interpreter exists. A directory left by an interrupted install looked
  ready and then failed several steps later with a misleading "check your
  internet connection". Such a venv is now recreated, and if creation
  fails on Debian/Ubuntu the error points at python3-venv, which is the
  actual cause there.
- The launch banner announced the URL as if the server were already up,
  while model loading still had a minute to go. It now says the interface
  will be available once "Running on local URL" appears.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 20:31:18 +03:00
Leonid PershinandClaude Opus 5 e9ea6b9bab feat: generation options for infer.py, and split out training deps
infer.py could only render a random example from examples/input_params:
there was no way to pass your own prompt, lyrics, duration or seed, so
using it for anything specific meant writing a separate script. Add
--prompt, --lyrics/--lyrics_file, --duration, --steps, --guidance_scale,
--scheduler, --cfg_type, --omega_scale, --seed and --format alongside the
existing runtime flags. Without --prompt the old random-example behaviour
is kept, so existing invocations are unaffected.

Also move the training-only packages out of the default install.
datasets, pytorch_lightning, matplotlib, tensorboard and tensorboardX are
imported by trainer.py and convert2hf_dataset.py, never on the inference
path, but every user was installing them — and datasets==3.4.1 is a hard
pin that drags constraints onto huggingface-hub. They now live in
requirements-train.txt behind the existing (previously ineffective)
"train" extra: pip install -e ".[train]".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 20:31:07 +03:00
Leonid PershinandClaude Opus 5 c7953dc4e0 fix: don't crash the UI on output files with custom names
create_text2music_ui() sorted the saved *_input_params.json files with
int(name.split('_')[1]), which assumes the generated
output_<timestamp>_<idx>_ shape. Output names are user-controlled — via
infer.py --output_path or a save_path from the UI — so any other name
raised ValueError while the Blocks were being built and took the whole
interface down before it could start:

    ValueError: invalid literal for int() with base 10: 'base'

Sort by mtime instead. That is what "previous generated input params"
means anyway (newest first) and it works for any filename; a file that
disappears between listdir() and getmtime() sorts last rather than
raising.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 20:30:58 +03:00
Leonid PershinandClaude Opus 5 0584397884 fix: write and read audio with soundfile instead of torchaudio
torchaudio 2.11 routes torchaudio.save()/load() through TorchCodec and
ignores the `backend` argument, so every generation died at the save
step with "ImportError: TorchCodec is required for save_with_torchcodec"
after the diffusion had already finished. Reference-audio loading
(audio2audio, repaint, extend) and the training dataset loader hit the
same wall.

soundfile is already a required dependency and covers all four output
formats the UI offers, so use it directly rather than pulling in
TorchCodec and its native FFmpeg stack:

- pipeline_ace_step.save_wav_file(): sf.write(), transposing
  (channels, samples) -> (samples, channels); drops the now-unused
  torchaudio import
- MusicDCAE.load_audio() and text2music_dataset: sf.read(dtype=float32,
  always_2d=True), transposed back to (channels, samples)

torchaudio is still used for Resample/MelScale transforms, which are
unaffected.

Verified end to end: 10s generation on an RTX 3060 in 9.7s, output is
valid non-silent 48kHz stereo; load_audio round-trips it; wav/mp3/ogg/
flac all write and read back.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-08 19:03:29 +03:00
14 changed files with 503 additions and 75 deletions
-1
View File
@@ -200,5 +200,4 @@ ui/components_demo.py
data_sampler_demo.py
pipeline_ace_step_demo.py
*.wav
start.sh
exps/*
+32 -5
View File
@@ -22,7 +22,7 @@
- [✨ Features](#-features)
- [📦 Installation](#-installation)
- [⚡ Quick Start (Windows)](#-quick-start-windows)
- [⚡ Quick Start](#-quick-start)
- [🚀 Usage](#-usage)
- [📱 User Interface Guide](#-user-interface-guide)
- [🔨 Train](#-train)
@@ -260,19 +260,30 @@ pip3 install torch torchvision torchaudio --index-url https://download.pytorch.o
pip install -e .
```
If you also intend to train or fine-tune, install the training extras as well (they are not needed for inference):
```bash
pip install -e ".[train]"
```
The ACE-Step application is now installed. The GUI works on Windows, macOS, and Linux. For instructions on how to run it, please see the [Usage](#-usage) section.
## ⚡ Quick Start (Windows)
## ⚡ Quick Start
This repository ships with [`start.bat`](./start.bat), which does everything for you: checks Python, creates the virtual environment, installs PyTorch with CUDA support, installs ACE-Step, and launches the web UI.
This repository ships with launcher scripts that do everything for you: check Python, create the virtual environment, install PyTorch with the right backend, install ACE-Step, and launch the web UI.
Just double-click `start.bat`, or run it from a command prompt:
**Windows** — double-click [`start.bat`](./start.bat), or run it from a command prompt:
```bat
start.bat
```
**Linux / macOS** — run [`start.sh`](./start.sh):
```bash
./start.sh
```
The first run takes a few minutes (roughly 3 GB of packages are downloaded). Model weights (~8 GB) are fetched automatically on the first generation. Later runs start immediately.
### Script flags
@@ -296,7 +307,7 @@ Flags can be combined, for example:
start.bat --lowvram --listen --port 7870
```
Defaults (port, GPU index, checkpoint path) live in the settings block at the top of `start.bat`.
Defaults (port, GPU index, checkpoint path) live in the settings block at the top of each script. In `start.sh` they can also be overridden with environment variables (`PORT=7870 ./start.sh`). On macOS the scripts install the MPS build of PyTorch and pass `--bf16 false` automatically.
## 🚀 Usage
@@ -321,6 +332,22 @@ acestep --checkpoint_path /path/to/checkpoint --port 7865 --device_id 0 --share
If you are using macOS, please use `--bf16 false` to avoid errors.
#### 🖥️ Command Line Generation
To generate without the web UI, use `infer.py`:
```bash
python infer.py \
--prompt "synth-pop, female vocal, warm analog synths, 110 bpm" \
--lyrics_file my_song.txt \
--duration 120 --steps 60 --seed 7 \
--format mp3 --output_path outputs/my_song.mp3
```
Run `python infer.py --help` for the full list. The main options are `--prompt`, `--lyrics` / `--lyrics_file`, `--duration`, `--steps`, `--guidance_scale`, `--scheduler`, `--cfg_type`, `--omega_scale`, `--seed`, `--format` and `--output_path`; the runtime flags (`--bf16`, `--cpu_offload`, `--overlapped_decode`, `--torch_compile`, `--device_id`) match the ones the GUI takes.
With no `--prompt`, the script keeps its original behaviour and generates from a random example in `examples/input_params`.
#### 🔍 API Usage
If you intend to integrate ACE-Step as a library into your own Python projects, you can install the latest version directly from GitHub using the following pip command.
+33 -5
View File
@@ -22,7 +22,7 @@
- [✨ Возможности](#-возможности)
- [📦 Установка](#-установка)
- [⚡ Быстрый старт на Windows](#-быстрый-старт-на-windows)
- [⚡ Быстрый старт](#-быстрый-старт)
- [🚀 Использование](#-использование)
- [📱 Описание интерфейса](#-описание-интерфейса)
- [🔨 Обучение](#-обучение)
@@ -261,19 +261,30 @@ pip3 install torch torchvision torchaudio --index-url https://download.pytorch.o
pip install -e .
```
Если планируете обучать или дообучать модель, поставьте дополнительно зависимости для обучения — для инференса они не нужны:
```bash
pip install -e ".[train]"
```
На этом установка завершена. Графический интерфейс работает на Windows, macOS и Linux. Как запускать — см. раздел [Использование](#-использование).
## ⚡ Быстрый старт на Windows
## ⚡ Быстрый старт
В репозитории есть скрипт [`start.bat`](./start.bat), который делает всё сам: проверяет Python, создаёт виртуальное окружение, ставит PyTorch с поддержкой CUDA, устанавливает ACE-Step и запускает веб-интерфейс.
В репозитории есть скрипты запуска, которые делают всё сами: проверяют Python, создают виртуальное окружение, ставят PyTorch с нужным бэкендом, устанавливают ACE-Step и запускают веб-интерфейс.
Достаточно дважды кликнуть по `start.bat` или запустить из командной строки:
**Windows** — достаточно дважды кликнуть по [`start.bat`](./start.bat) или запустить из командной строки:
```bat
start.bat
```
**Linux / macOS** — запустите [`start.sh`](./start.sh):
```bash
./start.sh
```
При первом запуске установка займёт несколько минут (скачивается около 3 ГБ пакетов). Веса модели (~8 ГБ) докачаются автоматически при первой генерации. Последующие запуски стартуют сразу.
### Флаги скрипта
@@ -284,6 +295,7 @@ start.bat
| `--cpu` | Запуск на процессоре, без CUDA (очень медленно, но работает без видеокарты NVIDIA) |
| `--share` | Публичная ссылка Gradio для доступа снаружи |
| `--port <N>` | Порт веб-интерфейса (по умолчанию 7865) |
| `--device <N>` | Номер видеокарты (по умолчанию 0) |
| `--listen` | Слушать `0.0.0.0`, чтобы зайти с других устройств в локальной сети |
| `--reinstall` | Полностью пересоздать виртуальное окружение с нуля |
| `--update` | Обновить зависимости в существующем окружении |
@@ -296,7 +308,7 @@ start.bat
start.bat --lowvram --listen --port 7870
```
Настройки по умолчанию (порт, номер GPU, путь к весам модели) задаются в блоке `==== НАСТРОЙКИ ====` в начале файла `start.bat`.
Настройки по умолчанию (порт, номер GPU, путь к весам модели) задаются в блоке `==== НАСТРОЙКИ ====` в начале каждого скрипта. В `start.sh` их можно переопределить переменными окружения (`PORT=7870 ./start.sh`). На macOS скрипт сам ставит сборку PyTorch с MPS и передаёт `--bf16 false`.
## 🚀 Использование
@@ -321,6 +333,22 @@ acestep --checkpoint_path /path/to/checkpoint --port 7865 --device_id 0 --share
На macOS используйте `--bf16 false`, чтобы избежать ошибок.
#### 🖥️ Генерация из командной строки
Чтобы генерировать без веб-интерфейса, используйте `infer.py`:
```bash
python infer.py \
--prompt "synth-pop, female vocal, warm analog synths, 110 bpm" \
--lyrics_file my_song.txt \
--duration 120 --steps 60 --seed 7 \
--format mp3 --output_path outputs/my_song.mp3
```
Полный список — `python infer.py --help`. Основные опции: `--prompt`, `--lyrics` / `--lyrics_file`, `--duration`, `--steps`, `--guidance_scale`, `--scheduler`, `--cfg_type`, `--omega_scale`, `--seed`, `--format`, `--output_path`. Флаги режима работы (`--bf16`, `--cpu_offload`, `--overlapped_decode`, `--torch_compile`, `--device_id`) те же, что у графического интерфейса.
Без `--prompt` скрипт ведёт себя как раньше и генерирует по случайному примеру из `examples/input_params`.
#### 🔍 Использование как библиотеки
Если вы хотите встроить ACE-Step как библиотеку в собственный Python-проект, можно поставить последнюю версию прямо из GitHub.
+10
View File
@@ -1,5 +1,15 @@
# Training Instruction
## 0. Install the Training Dependencies
Training needs a few packages that a plain inference install does not pull in
(`datasets`, `pytorch_lightning`, `matplotlib`, `tensorboard`, `tensorboardX`).
Install them with the `train` extra:
```bash
pip install -e ".[train]"
```
## 1. Data Preparation
### Required File Format
+9 -3
View File
@@ -10,6 +10,7 @@ import os
import torch
from diffusers import AutoencoderDC
import torchaudio
import soundfile as sf
import torchvision.transforms as transforms
from diffusers.models.modeling_utils import ModelMixin
from diffusers.loaders import FromOriginalModelMixin
@@ -60,7 +61,11 @@ class MusicDCAE(ModelMixin, ConfigMixin, FromOriginalModelMixin):
self.shift_factor = -1.9091
def load_audio(self, audio_path):
audio, sr = torchaudio.load(audio_path)
# Read with soundfile rather than torchaudio.load(): since torchaudio
# 2.11 the latter routes I/O through TorchCodec, an extra native
# dependency we do not require.
data, sr = sf.read(audio_path, dtype="float32", always_2d=True)
audio = torch.from_numpy(data.T)
if audio.shape[0] == 1:
audio = audio.repeat(2, 1)
return audio, sr
@@ -362,7 +367,8 @@ class MusicDCAE(ModelMixin, ConfigMixin, FromOriginalModelMixin):
if __name__ == "__main__":
audio, sr = torchaudio.load("test.wav")
_data, sr = sf.read("test.wav", dtype="float32", always_2d=True)
audio = torch.from_numpy(_data.T)
audio_lengths = torch.tensor([audio.shape[1]])
audios = audio.unsqueeze(0)
@@ -378,5 +384,5 @@ if __name__ == "__main__":
print("latents shape: ", latents.shape)
print("latent_lengths: ", latent_lengths)
print("sr: ", sr)
torchaudio.save("test_reconstructed.wav", pred_wavs[0], sr)
sf.write("test_reconstructed.wav", pred_wavs[0].float().cpu().transpose(0, 1).numpy(), sr)
print("test_reconstructed.wav")
+12 -8
View File
@@ -12,6 +12,7 @@ import os
import re
import torch
import soundfile as sf
from loguru import logger
from tqdm import tqdm
import json
@@ -46,7 +47,6 @@ from acestep.apg_guidance import (
cfg_zero_star,
cfg_double_condition_forward,
)
import torchaudio
from .cpu_offload import cpu_offload
@@ -1405,13 +1405,17 @@ class ACEStepPipeline:
else:
output_path_wav = save_path
target_wav = target_wav.float()
backend = "soundfile"
if format == "ogg":
backend = "sox"
logger.info(f"Saving audio to {output_path_wav} using backend {backend}")
torchaudio.save(
output_path_wav, target_wav, sample_rate=sample_rate, format=format, backend=backend
target_wav = target_wav.float().cpu()
logger.info(f"Saving audio to {output_path_wav}")
# Write with soundfile rather than torchaudio.save(): since torchaudio
# 2.11 the latter ignores the `backend` argument and routes everything
# through TorchCodec, an extra native dependency we do not require.
# soundfile expects (samples, channels), torch tensors are (channels, samples).
sf.write(
output_path_wav,
target_wav.transpose(0, 1).numpy(),
sample_rate,
format=format.upper(),
)
return output_path_wav
+5 -1
View File
@@ -7,6 +7,7 @@ from loguru import logger
import time
import traceback
import torchaudio
import soundfile as sf
from pathlib import Path
import re
from acestep.language_segmentation import LangSegment
@@ -398,7 +399,10 @@ class Text2MusicDataset(Dataset):
filename = item["filename"]
sr = 48000
try:
audio, sr = torchaudio.load(filename)
# soundfile instead of torchaudio.load(): torchaudio 2.11 routes
# I/O through TorchCodec, an extra native dependency.
_data, sr = sf.read(filename, dtype="float32", always_2d=True)
audio = torch.from_numpy(_data.T)
except Exception as e:
logger.error(f"Failed to load audio {item}: {e}")
return None
+11 -1
View File
@@ -101,7 +101,17 @@ def create_text2music_ui(
if not os.path.isdir(output_file_dir):
os.makedirs(output_file_dir, exist_ok=True)
json_files = [f for f in os.listdir(output_file_dir) if f.endswith('.json')]
json_files.sort(reverse=True, key=lambda x: int(x.split('_')[1]))
def _mtime(name):
# Output filenames are user-controlled (infer.py --output_path, or the
# save_path passed from the UI), so a timestamp cannot be parsed out of
# them: doing so used to raise ValueError and take the whole UI down.
try:
return os.path.getmtime(os.path.join(output_file_dir, name))
except OSError:
return 0.0
json_files.sort(key=_mtime, reverse=True)
output_files = gr.Dropdown(choices=json_files, label="Select previous generated input params", scale=9, interactive=True)
load_bnt = gr.Button("Load", variant="primary", scale=1)
+114 -29
View File
@@ -48,7 +48,66 @@ def sample_data(json_data):
)
@click.option("--device_id", type=int, default=0, help="Device ID to use")
@click.option("--output_path", type=str, default=None, help="Path to save the output")
def main(checkpoint_path, bf16, torch_compile, cpu_offload, overlapped_decode, device_id, output_path):
# --- generation parameters -------------------------------------------------
# Without --prompt the script keeps its original behaviour and generates from a
# random example in examples/input_params.
@click.option(
"--prompt",
type=str,
default=None,
help="Style tags or description, comma separated. If omitted, a random example is used.",
)
@click.option("--lyrics", type=str, default=None, help="Lyrics, with [verse]/[chorus] tags.")
@click.option(
"--lyrics_file",
type=click.Path(exists=True, dir_okay=False),
default=None,
help="Read lyrics from a UTF-8 file. Takes precedence over --lyrics.",
)
@click.option("--duration", type=float, default=60.0, help="Audio duration in seconds (-1 for random).")
@click.option("--steps", type=int, default=60, help="Number of inference steps.")
@click.option("--guidance_scale", type=float, default=15.0, help="Guidance scale.")
@click.option(
"--scheduler",
type=click.Choice(["euler", "heun", "pingpong"]),
default="euler",
help="Scheduler type.",
)
@click.option(
"--cfg_type",
type=click.Choice(["cfg", "apg", "cfg_star"]),
default="apg",
help="CFG type. apg is recommended.",
)
@click.option("--omega_scale", type=float, default=10.0, help="Granularity scale.")
@click.option("--seed", type=str, default=None, help="Manual seeds, comma separated. Random if omitted.")
@click.option(
"--format",
"audio_format",
type=click.Choice(["wav", "mp3", "ogg", "flac"]),
default="wav",
help="Output audio format.",
)
def main(
checkpoint_path,
bf16,
torch_compile,
cpu_offload,
overlapped_decode,
device_id,
output_path,
prompt,
lyrics,
lyrics_file,
duration,
steps,
guidance_scale,
scheduler,
cfg_type,
omega_scale,
seed,
audio_format,
):
os.environ["CUDA_VISIBLE_DEVICES"] = str(device_id)
model_demo = ACEStepPipeline(
@@ -58,44 +117,70 @@ def main(checkpoint_path, bf16, torch_compile, cpu_offload, overlapped_decode, d
cpu_offload=cpu_offload,
overlapped_decode=overlapped_decode
)
print(model_demo)
data_sampler = DataSampler()
if lyrics_file is not None:
with open(lyrics_file, "r", encoding="utf-8") as f:
lyrics = f.read()
json_data = data_sampler.sample()
json_data = sample_data(json_data)
print(json_data)
if prompt is None:
# No prompt given: keep the original behaviour and use a random example.
data_sampler = DataSampler()
json_data = data_sampler.sample()
(
audio_duration,
prompt,
sampled_lyrics,
infer_step,
sampled_guidance_scale,
scheduler_type,
sampled_cfg_type,
sampled_omega_scale,
manual_seeds,
guidance_interval,
guidance_interval_decay,
min_guidance_scale,
use_erg_tag,
use_erg_lyric,
use_erg_diffusion,
oss_steps,
guidance_scale_text,
guidance_scale_lyric,
) = sample_data(json_data)
# Explicit options still win over the sampled example.
lyrics = lyrics if lyrics is not None else sampled_lyrics
manual_seeds = seed if seed is not None else manual_seeds
else:
audio_duration = duration
lyrics = lyrics if lyrics is not None else "[instrumental]"
infer_step = steps
sampled_guidance_scale = guidance_scale
scheduler_type = scheduler
sampled_cfg_type = cfg_type
sampled_omega_scale = omega_scale
manual_seeds = seed
guidance_interval = 0.5
guidance_interval_decay = 0.0
min_guidance_scale = 3.0
use_erg_tag = True
use_erg_lyric = True
use_erg_diffusion = True
oss_steps = None
guidance_scale_text = 0.0
guidance_scale_lyric = 0.0
(
audio_duration,
prompt,
lyrics,
infer_step,
guidance_scale,
scheduler_type,
cfg_type,
omega_scale,
manual_seeds,
guidance_interval,
guidance_interval_decay,
min_guidance_scale,
use_erg_tag,
use_erg_lyric,
use_erg_diffusion,
oss_steps,
guidance_scale_text,
guidance_scale_lyric,
) = json_data
click.echo(f"prompt: {prompt}")
click.echo(f"duration: {audio_duration}s, steps: {infer_step}, seeds: {manual_seeds}")
model_demo(
format=audio_format,
audio_duration=audio_duration,
prompt=prompt,
lyrics=lyrics,
infer_step=infer_step,
guidance_scale=guidance_scale,
guidance_scale=sampled_guidance_scale,
scheduler_type=scheduler_type,
cfg_type=cfg_type,
omega_scale=omega_scale,
cfg_type=sampled_cfg_type,
omega_scale=sampled_omega_scale,
manual_seeds=manual_seeds,
guidance_interval=guidance_interval,
guidance_interval_decay=guidance_interval_decay,
+7
View File
@@ -0,0 +1,7 @@
# Training-only dependencies (trainer.py, convert2hf_dataset.py).
# Install with: pip install -e ".[train]"
datasets==3.4.1
pytorch_lightning==2.5.1
matplotlib==3.10.1
tensorboard
tensorboardX
-5
View File
@@ -1,12 +1,9 @@
datasets==3.4.1
diffusers>=0.33.0
gradio>=6.0.0
librosa==0.11.0
loguru==0.7.3
matplotlib==3.10.1
numpy
pypinyin==0.53.0
pytorch_lightning==2.5.1
soundfile==0.13.1
torch
torchaudio
@@ -22,5 +19,3 @@ cutlet
fugashi[unidic-lite]
click
peft
tensorboard
tensorboardX
+14 -6
View File
@@ -1,5 +1,16 @@
from setuptools import setup, find_namespace_packages
def read_requirements(path):
"""Read a requirements file, skipping comments and blank lines."""
with open(path, encoding="utf-8") as f:
return [
line.strip()
for line in f
if line.strip() and not line.lstrip().startswith("#")
]
setup(
name="ace_step",
description="ACE Step: A Step Towards Music Generation Foundation Model",
@@ -7,7 +18,7 @@ setup(
long_description_content_type="text/markdown",
version="0.2.0",
packages=find_namespace_packages(),
install_requires=open("requirements.txt", encoding="utf-8").read().splitlines(),
install_requires=read_requirements("requirements.txt"),
author="ACE Studio, StepFun AI",
license="Apache 2.0",
classifiers=[
@@ -25,10 +36,7 @@ setup(
"acestep.models.lyrics_utils": ["vocab.json"], # Specify the relative path to vocab.json
},
extras_require={
"train": [
"peft",
"tensorboard",
"tensorboardX"
]
# Only needed to train or fine-tune; inference does not import these.
"train": read_requirements("requirements-train.txt"),
},
)
+23 -11
View File
@@ -68,8 +68,15 @@ if "%DO_REINSTALL%"=="1" (
)
REM ------------------------- поиск Python -------------------------
if exist "%VENV_PY%" goto venv_ready
REM Рабочим считаем окружение, в котором есть и python, и pip: каталог от
REM прерванной установки выглядит как готовый, но валится дальше с невнятной
REM ошибкой про интернет.
if not exist "%VENV_PY%" goto venv_create
"%VENV_PY%" -m pip --version >nul 2>&1 && goto venv_ready
echo [1/4] Окружение "%VENV_DIR%" неработоспособно, пересоздаю...
rmdir /s /q "%VENV_DIR%"
:venv_create
echo [1/4] Ищу подходящий Python...
set "SYS_PY="
for %%V in (3.12 3.11 3.10 3.13) do (
@@ -92,14 +99,9 @@ echo Найден Python %PYVER% (%SYS_PY%)
echo [1/4] Создаю виртуальное окружение в "%VENV_DIR%"...
%SYS_PY% -m venv "%VENV_DIR%"
if errorlevel 1 (
echo [ОШИБКА] Не удалось создать виртуальное окружение.
goto fail
)
if not exist "%VENV_PY%" (
echo [ОШИБКА] Виртуальное окружение создано некорректно: нет "%VENV_PY%".
goto fail
)
if errorlevel 1 goto venv_failed
if not exist "%VENV_PY%" goto venv_failed
"%VENV_PY%" -m pip --version >nul 2>&1 || goto venv_failed
set "FRESH_VENV=1"
:venv_ready
@@ -205,9 +207,12 @@ if "%OPT_LOWVRAM%"=="1" set "ARGS=%ARGS% --cpu_offload true --overlapped_decode
echo [4/4] Запускаю веб-интерфейс...
echo.
echo Адрес: http://%SERVER_NAME%:%PORT%
if "%OPT_LOWVRAM%"=="1" echo Режим: экономия видеопамяти
echo Первый запуск скачивает веса модели (~8 ГБ) - наберитесь терпения.
echo Идёт загрузка моделей, это занимает время.
echo При первом запуске дополнительно скачиваются веса (~8 ГБ).
echo.
echo Интерфейс будет доступен на http://%SERVER_NAME%:%PORT%
echo когда ниже появится строка "Running on local URL".
echo Остановить: Ctrl+C в этом окне.
echo.
@@ -240,6 +245,13 @@ echo.
goto success
REM ------------------------- завершение -------------------------
:venv_failed
echo.
echo [ОШИБКА] Не удалось создать рабочее виртуальное окружение в "%VENV_DIR%".
echo Переустановите Python с https://www.python.org/downloads/,
echo отметив "Add Python to PATH", и запустите "%SCRIPT_NAME% --reinstall".
goto fail
:fail
echo.
pause
Executable
+233
View File
@@ -0,0 +1,233 @@
#!/usr/bin/env bash
# ACE-Step: настройка окружения и запуск веб-интерфейса на Linux / macOS.
# Windows-аналог — start.bat.
set -uo pipefail
cd "$(dirname "$0")"
# ============================ НАСТРОЙКИ ============================
VENV_DIR="${VENV_DIR:-venv}" # каталог виртуального окружения
PORT="${PORT:-7865}" # порт веб-интерфейса
SERVER_NAME="${SERVER_NAME:-127.0.0.1}" # 0.0.0.0 — доступ из локальной сети
DEVICE_ID="${DEVICE_ID:-0}" # номер видеокарты
CHECKPOINT_PATH="${CHECKPOINT_PATH:-}" # пусто — скачать в ~/.cache/ace-step
# Сборка PyTorch под CUDA (cu126 / cu124 / cu121). Только для Linux.
TORCH_INDEX="${TORCH_INDEX:-https://download.pytorch.org/whl/cu126}"
# ==================================================================
SCRIPT_NAME="$(basename "$0")"
OPT_LOWVRAM=0
OPT_CPU=0
OPT_SHARE=0
DO_SETUP_ONLY=0
DO_REINSTALL=0
DO_UPDATE=0
usage() {
cat <<EOF
Использование: ./$SCRIPT_NAME [флаги]
--lowvram Режим экономии видеопамяти (~8 ГБ VRAM)
--cpu Запуск на процессоре, без CUDA (очень медленно)
--share Публичная ссылка Gradio
--port <N> Порт веб-интерфейса (по умолчанию $PORT)
--device <N> Номер видеокарты (по умолчанию $DEVICE_ID)
--listen Слушать 0.0.0.0 (доступ из локальной сети)
--reinstall Пересоздать виртуальное окружение с нуля
--update Обновить зависимости
--setup Только установка, без запуска
--help Эта справка
Настройки по умолчанию — в блоке НАСТРОЙКИ в начале файла,
их можно переопределить переменными окружения (PORT=7870 ./$SCRIPT_NAME).
EOF
}
die() {
echo
echo "[ОШИБКА] $*" >&2
exit 1
}
while [ $# -gt 0 ]; do
case "$1" in
--help|-h) usage; exit 0 ;;
--lowvram) OPT_LOWVRAM=1; shift ;;
--cpu) OPT_CPU=1; shift ;;
--share) OPT_SHARE=1; shift ;;
--setup) DO_SETUP_ONLY=1; shift ;;
--reinstall) DO_REINSTALL=1; shift ;;
--update) DO_UPDATE=1; shift ;;
--listen) SERVER_NAME="0.0.0.0"; shift ;;
--port) PORT="${2:?--port требует значение}"; shift 2 ;;
--device) DEVICE_ID="${2:?--device требует значение}"; shift 2 ;;
*)
echo "[ОШИБКА] Неизвестный аргумент: $1" >&2
echo "Запустите ./$SCRIPT_NAME --help для справки." >&2
exit 1 ;;
esac
done
echo
echo "=========================================="
echo " ACE-Step - генерация музыки"
echo "=========================================="
echo
case "$(uname -s)" in
Darwin) IS_MAC=1 ;;
*) IS_MAC=0 ;;
esac
VENV_PY="$PWD/$VENV_DIR/bin/python"
# Рабочим считаем окружение, в котором есть и python, и pip: каталог от
# прерванной установки (или venv без ensurepip) выглядит как готовый, но валится
# дальше с невнятной ошибкой.
venv_ok() {
[ -x "$VENV_PY" ] && "$VENV_PY" -m pip --version >/dev/null 2>&1
}
venv_failed() {
echo >&2
echo "[ОШИБКА] Не удалось создать рабочее виртуальное окружение в \"$VENV_DIR\"." >&2
if [ "$IS_MAC" = 0 ] && command -v apt >/dev/null 2>&1; then
echo "На Debian/Ubuntu для этого нужен отдельный пакет:" >&2
echo " sudo apt install python3-venv" >&2
fi
exit 1
}
if [ "$DO_REINSTALL" = 1 ] && [ -d "$VENV_DIR" ]; then
echo "[1/4] Удаляю старое окружение \"$VENV_DIR\"..."
rm -rf "$VENV_DIR"
fi
# ------------------------- поиск Python -------------------------
if venv_ok; then
echo "[1/4] Виртуальное окружение найдено: $VENV_DIR"
else
if [ -d "$VENV_DIR" ]; then
echo "[1/4] Окружение \"$VENV_DIR\" неработоспособно, пересоздаю..."
rm -rf "$VENV_DIR"
fi
echo "[1/4] Ищу подходящий Python..."
SYS_PY=""
for candidate in python3.12 python3.11 python3.10 python3.13 python3; do
if command -v "$candidate" >/dev/null 2>&1 &&
"$candidate" -c 'import sys; sys.exit(0 if sys.version_info >= (3,10) else 1)' 2>/dev/null; then
SYS_PY="$candidate"
break
fi
done
[ -n "$SYS_PY" ] || die "Не найден Python 3.10 или новее. Установите его и повторите."
echo " Найден Python $("$SYS_PY" -c 'import sys; print(sys.version.split()[0])') ($SYS_PY)"
echo "[1/4] Создаю виртуальное окружение в \"$VENV_DIR\"..."
"$SYS_PY" -m venv "$VENV_DIR" || venv_failed
venv_ok || venv_failed
fi
# ------------------------- зависимости -------------------------
echo "[2/4] Проверяю зависимости..."
NEED_TORCH=0
"$VENV_PY" -c "import importlib.util,sys; sys.exit(0 if importlib.util.find_spec('torch') else 1)" 2>/dev/null || NEED_TORCH=1
# Проверяем именно установку пакета: каталог acestep лежит рядом со скриптом,
# поэтому find_spec('acestep') сработал бы и без установленных зависимостей.
NEED_ACESTEP=0
"$VENV_PY" -c "import importlib.metadata as md, importlib.util as u, sys; md.version('ace_step'); sys.exit(0 if u.find_spec('click') and u.find_spec('gradio') else 1)" 2>/dev/null || NEED_ACESTEP=1
if [ "$DO_UPDATE" = 1 ]; then
NEED_TORCH=1
NEED_ACESTEP=1
fi
if [ "$NEED_TORCH" = 1 ] || [ "$NEED_ACESTEP" = 1 ]; then
echo " Обновляю pip..."
"$VENV_PY" -m pip install --upgrade pip setuptools wheel --quiet ||
die "Не удалось обновить pip. Проверьте подключение к интернету."
fi
if [ "$NEED_TORCH" = 1 ]; then
if [ "$IS_MAC" = 1 ]; then
# На macOS колёса с PyPI уже собраны с поддержкой MPS.
echo " Устанавливаю PyTorch (macOS/MPS). Это займёт несколько минут..."
"$VENV_PY" -m pip install --upgrade torch torchvision torchaudio
elif [ "$OPT_CPU" = 1 ]; then
echo " Устанавливаю PyTorch для CPU. Это займёт несколько минут..."
"$VENV_PY" -m pip install --upgrade torch torchvision torchaudio \
--index-url https://download.pytorch.org/whl/cpu
else
echo " Устанавливаю PyTorch с поддержкой CUDA. Это займёт несколько минут..."
"$VENV_PY" -m pip install --upgrade torch torchvision torchaudio --index-url "$TORCH_INDEX"
fi || die "Не удалось установить PyTorch. Если у вас другая версия CUDA, поменяйте TORCH_INDEX."
fi
if [ "$NEED_ACESTEP" = 1 ]; then
echo " Устанавливаю ACE-Step и зависимости..."
"$VENV_PY" -m pip install -e . || die "Не удалось установить ACE-Step."
fi
if [ "$OPT_LOWVRAM" = 1 ] && [ "$IS_MAC" = 0 ]; then
if ! "$VENV_PY" -c "import importlib.util,sys; sys.exit(0 if importlib.util.find_spec('triton') else 1)" 2>/dev/null; then
echo " Режим экономии VRAM: устанавливаю triton..."
"$VENV_PY" -m pip install triton --quiet ||
echo "[ВНИМАНИЕ] triton не установился, --torch_compile может не заработать."
fi
fi
# ------------------------- проверка устройства -------------------------
echo "[3/4] Проверяю устройство..."
BF16=true
if [ "$OPT_CPU" = 1 ]; then
echo " Принудительный режим CPU. Генерация будет очень медленной."
DEVICE_ID=-1
BF16=false
elif [ "$IS_MAC" = 1 ]; then
# На MPS bfloat16 приводит к ошибкам, см. README.
echo " macOS: используется MPS, bf16 отключён."
BF16=false
else
GPUINFO="$("$VENV_PY" -c "import torch; print((torch.cuda.get_device_name(0) + ' - ' + str(round(torch.cuda.get_device_properties(0).total_memory/1073741824, 1)) + ' GB VRAM') if torch.cuda.is_available() else 'NO_CUDA')" 2>/dev/null || echo NO_CUDA)"
if [ "$GPUINFO" = "NO_CUDA" ]; then
echo
echo "[ВНИМАНИЕ] CUDA недоступна - модель будет работать на процессоре (очень медленно)."
echo "Если у вас есть видеокарта NVIDIA, обновите драйвер и переустановите PyTorch:"
echo " ./$SCRIPT_NAME --update"
echo
else
echo " $GPUINFO"
fi
fi
if [ "$DO_SETUP_ONLY" = 1 ]; then
echo
echo "Установка завершена. Для запуска выполните ./$SCRIPT_NAME"
exit 0
fi
# ------------------------- запуск -------------------------
ARGS=(--port "$PORT" --server_name "$SERVER_NAME" "--device_id=$DEVICE_ID" --bf16 "$BF16")
[ -n "$CHECKPOINT_PATH" ] && ARGS+=(--checkpoint_path "$CHECKPOINT_PATH")
[ "$OPT_SHARE" = 1 ] && ARGS+=(--share true)
if [ "$OPT_LOWVRAM" = 1 ]; then
ARGS+=(--cpu_offload true --overlapped_decode true)
[ "$IS_MAC" = 0 ] && ARGS+=(--torch_compile true)
fi
echo "[4/4] Запускаю веб-интерфейс..."
echo
[ "$OPT_LOWVRAM" = 1 ] && echo " Режим: экономия видеопамяти"
echo " Идёт загрузка моделей, это занимает время."
echo " При первом запуске дополнительно скачиваются веса (~8 ГБ)."
echo
echo " Интерфейс будет доступен на http://$SERVER_NAME:$PORT"
echo " когда ниже появится строка \"Running on local URL\"."
echo " Остановить: Ctrl+C в этом окне."
echo
exec "$VENV_PY" -m acestep.gui "${ARGS[@]}"