diff --git a/.gitignore b/.gitignore index 21a63c9..c35f8da 100644 --- a/.gitignore +++ b/.gitignore @@ -90,3 +90,6 @@ comfyui/ # External editors (wavacity is 184MB - clone separately if needed) wavacity-editor/ + +# Script logs +logs/ diff --git a/README.md b/README.md index 7819096..15a8cf3 100644 --- a/README.md +++ b/README.md @@ -144,16 +144,57 @@ | Requirement | Specification | |-------------|---------------| | **Node.js** | 18 or higher | -| **Python** | 3.10+ (3.11 recommended) | -| **NVIDIA GPU** | 8GB+ VRAM (12GB+ recommended) | +| **Python** | 3.10+ (3.11 recommended) OR Windows Portable Package | +| **NVIDIA GPU** | 4GB+ VRAM (works without LLM), 12GB+ recommended (with LLM) | +| **CUDA** | 12.8 (for Windows Portable Package) | | **FFmpeg** | For audio processing | -| **uv** | Python package manager (recommended) | +| **uv** | Python package manager (recommended for standard install) | --- ## ⚡ Quick Start -### Linux / macOS +### 🪟 Windows - One-Click Start (Easiest!) +```batch +cd ace-step-ui +start-all.bat +``` +**That's it!** This starts everything: API + Backend + Frontend in one command. + +> **Note:** By default, it looks for ACE-Step in `..\ACE-Step-1.5`. +> If yours is elsewhere, set `ACESTEP_PATH` first: +> ```batch +> set ACESTEP_PATH=C:\path\to\ACE-Step-1.5 +> start-all.bat +> ``` + +### 🪟 Windows - Manual Start +```batch +REM 1. Start ACE-Step API +cd C:\ACE-Step-1.5 +python_embeded\python acestep\api_server.py + +REM 2. Start ACE-Step UI (in another terminal) +cd ace-step-ui +start.bat +``` + +### Linux / macOS - One-Click Start (Easiest!) +```bash +cd ace-step-ui +./start-all.sh +``` +**That's it!** This starts everything: API + Backend + Frontend in one command. + +> **Note:** By default, it looks for ACE-Step in `../ACE-Step-1.5`. +> If yours is elsewhere, set `ACESTEP_PATH` first: +> ```bash +> export ACESTEP_PATH=/path/to/ACE-Step-1.5 +> ./start-all.sh +> ``` +> **To stop:** `./stop-all.sh` + +### Linux / macOS - Manual Start ```bash # 1. Start ACE-Step API (in ACE-Step-1.5 directory) cd /path/to/ACE-Step-1.5 @@ -164,7 +205,7 @@ cd ace-step-ui ./start.sh ``` -### Windows +### Windows (Standard Installation) ```batch REM 1. Start ACE-Step API (in ACE-Step-1.5 directory) cd C:\path\to\ACE-Step-1.5 @@ -183,6 +224,22 @@ Open **http://localhost:3000** and start creating! ### 1. Install ACE-Step (The AI Engine) +#### 🪟 Windows Portable Package (Recommended for Windows) + +**The easiest way to get started on Windows!** This package includes everything pre-configured: + +1. **Download** [ACE-Step-1.5.7z](https://files.acemusic.ai/acemusic/win/ACE-Step-1.5.7z) (~5GB) +2. **Extract** to `C:\ACE-Step-1.5` (or your preferred location) +3. **Done!** The package includes `python_embeded` with all dependencies + +✅ **Works with 4GB GPU** - No LLM installation required +✅ **CUDA 12.8** included +✅ **Zero setup hassle** + +> **Note:** Thinking Mode (LLM features) is automatically disabled on GPUs with <12GB VRAM. You can still enable it manually if you have 12GB+. + +#### Standard Installation (All Platforms) + ```bash # Clone ACE-Step 1.5 - the open source Suno alternative git clone https://github.com/ace-step/ACE-Step-1.5 @@ -242,13 +299,19 @@ copy server\.env.example server\.env ### Step 1: Start ACE-Step API Server +**🪟 Windows Portable Package:** +```batch +cd C:\ACE-Step-1.5 +python_embeded\python acestep\api_server.py +``` + **Linux / macOS:** ```bash cd /path/to/ACE-Step-1.5 uv run acestep-api --port 8001 ``` -**Windows:** +**Windows (Standard Installation):** ```batch cd C:\path\to\ACE-Step-1.5 uv run acestep-api --port 8001 @@ -334,9 +397,11 @@ Full control over every parameter: | Issue | Solution | |-------|----------| -| **ACE-Step API not reachable** | Ensure `uv run acestep-api --port 8001` is running | -| **CUDA out of memory** | Close other GPU apps, reduce duration | -| **Songs show 0:00 duration** | Install FFmpeg: `sudo apt install ffmpeg` | +| **ACE-Step API not reachable** | Ensure API server is running (see Usage section) | +| **CUDA out of memory** | Close other GPU apps, reduce duration, or disable Thinking Mode | +| **4GB GPU - Out of memory** | Make sure **Thinking Mode is OFF** (it's off by default). LLM features require 12GB+ | +| **AttributeError: 'NoneType'** | Update to latest ACE-Step-1.5 (fix merged in PR #109) | +| **Songs show 0:00 duration** | Install FFmpeg: `sudo apt install ffmpeg` (Linux) or download from [ffmpeg.org](https://ffmpeg.org) (Windows) | | **LAN access not working** | Check firewall allows ports 3000 and 3001 | --- diff --git a/components/CreatePanel.tsx b/components/CreatePanel.tsx index 721be1f..ab613ba 100644 --- a/components/CreatePanel.tsx +++ b/components/CreatePanel.tsx @@ -102,7 +102,7 @@ export const CreatePanel: React.FC = ({ onGenerate, isGenerati const [guidanceScale, setGuidanceScale] = useState(7.0); const [randomSeed, setRandomSeed] = useState(true); const [seed, setSeed] = useState(-1); - const [thinking, setThinking] = useState(true); + const [thinking, setThinking] = useState(false); // Default false for GPU compatibility const [audioFormat, setAudioFormat] = useState<'mp3' | 'flac'>('mp3'); const [inferenceSteps, setInferenceSteps] = useState(8); const [inferMethod, setInferMethod] = useState<'ode' | 'sde'>('ode'); diff --git a/server/src/routes/generate.ts b/server/src/routes/generate.ts index 4747199..4a24a5d 100644 --- a/server/src/routes/generate.ts +++ b/server/src/routes/generate.ts @@ -26,6 +26,9 @@ const audioUpload = multer({ fileFilter: (_req, file, cb) => { const allowedTypes = [ 'audio/mpeg', + 'audio/mp3', // Alternative MIME type for MP3 + 'audio/mpeg3', + 'audio/x-mpeg-3', 'audio/wav', 'audio/x-wav', 'audio/flac', @@ -35,10 +38,15 @@ const audioUpload = multer({ 'audio/ogg', 'audio/webm', ]; - if (allowedTypes.includes(file.mimetype)) { + + // Also check file extension as fallback + const allowedExtensions = ['.mp3', '.wav', '.flac', '.m4a', '.aac', '.ogg', '.webm', '.opus']; + const fileExt = file.originalname.toLowerCase().match(/\.[^.]+$/)?.[0]; + + if (allowedTypes.includes(file.mimetype) || (fileExt && allowedExtensions.includes(fileExt))) { cb(null, true); } else { - cb(new Error('Invalid file type. Only common audio formats are allowed.')); + cb(new Error(`Invalid file type. Only common audio formats are allowed. Received: ${file.mimetype} (${file.originalname})`)); } } }); diff --git a/server/src/services/acestep.ts b/server/src/services/acestep.ts index e7f1108..a60765d 100644 --- a/server/src/services/acestep.ts +++ b/server/src/services/acestep.ts @@ -92,7 +92,7 @@ async function isApiAvailable(): Promise { if (response.ok) { const data = await response.json(); - apiAvailableCache = data.status === 'ok' || data.healthy === true; + apiAvailableCache = data.status === 'ok' || data.healthy === true || data.data?.status === 'ok'; console.log(`[ACE-Step] API available at ${ACESTEP_API}: ${apiAvailableCache}`); return apiAvailableCache; } @@ -133,6 +133,10 @@ async function submitToApi(params: GenerationParams): Promise<{ taskId: string } vocal_language: params.vocalLanguage || 'en', use_random_seed: params.randomSeed !== false, shift: params.shift ?? 3.0, + thinking: params.thinking ?? false, // Respect frontend choice, default false for GPU compatibility + use_cot_caption: false, // Explicitly disable CoT features that require LLM + use_cot_language: false, // Explicitly disable CoT features that require LLM + use_cot_metas: false, // Explicitly disable CoT features that require LLM }; if (params.bpm && params.bpm > 0) body.bpm = params.bpm; @@ -148,13 +152,16 @@ async function submitToApi(params: GenerationParams): Promise<{ taskId: string } if (params.repaintingEnd !== undefined && params.repaintingEnd > 0) body.repainting_end = params.repaintingEnd; if (params.audioCoverStrength !== undefined && params.audioCoverStrength !== 1.0) body.audio_cover_strength = params.audioCoverStrength; if (params.instruction) body.instruction = params.instruction; - if (params.thinking) body.thinking = true; - if (params.lmTemperature !== undefined) body.lm_temperature = params.lmTemperature; - if (params.lmCfgScale !== undefined) body.lm_cfg_scale = params.lmCfgScale; - if (params.lmTopK !== undefined && params.lmTopK > 0) body.lm_top_k = params.lmTopK; - if (params.lmTopP !== undefined) body.lm_top_p = params.lmTopP; - if (params.useCotCaption !== undefined) body.use_cot_caption = params.useCotCaption; - if (params.useCotLanguage !== undefined) body.use_cot_language = params.useCotLanguage; + // LLM and CoT parameters only sent when thinking mode is enabled + if (params.thinking) { + if (params.lmTemperature !== undefined) body.lm_temperature = params.lmTemperature; + if (params.lmCfgScale !== undefined) body.lm_cfg_scale = params.lmCfgScale; + if (params.lmTopK !== undefined && params.lmTopK > 0) body.lm_top_k = params.lmTopK; + if (params.lmTopP !== undefined) body.lm_top_p = params.lmTopP; + if (params.useCotCaption !== undefined) body.use_cot_caption = params.useCotCaption; + if (params.useCotLanguage !== undefined) body.use_cot_language = params.useCotLanguage; + if (params.useCotMetas !== undefined) body.use_cot_metas = params.useCotMetas; + } if (params.useAdg) body.use_adg = true; if (params.cfgIntervalStart !== undefined && params.cfgIntervalStart > 0) body.cfg_interval_start = params.cfgIntervalStart; if (params.cfgIntervalEnd !== undefined && params.cfgIntervalEnd < 1.0) body.cfg_interval_end = params.cfgIntervalEnd; @@ -187,7 +194,7 @@ async function submitToApi(params: GenerationParams): Promise<{ taskId: string } } const result = await response.json(); - const taskId = result.data?.job_id || result.job_id; + const taskId = result.data?.task_id || result.data?.job_id || result.job_id || result.task_id; if (!taskId) { throw new Error('No task ID returned from API'); } @@ -260,7 +267,10 @@ async function pollApiResult(taskId: string, maxWaitMs = 600000): Promise { - const url = `${ACESTEP_API}/v1/audio?path=${encodeURIComponent(audioPath)}`; + // Check if audioPath is already a relative URL (starts with /v1/audio) + const url = audioPath.startsWith('/v1/audio') + ? `${ACESTEP_API}${audioPath}` + : `${ACESTEP_API}/v1/audio?path=${encodeURIComponent(audioPath)}`; const response = await fetch(url); if (!response.ok) { diff --git a/start-all.bat b/start-all.bat new file mode 100644 index 0000000..6107083 --- /dev/null +++ b/start-all.bat @@ -0,0 +1,112 @@ +@echo off +REM ACE-Step UI Complete Startup Script for Windows +REM Starts ACE-Step API + Backend + Frontend +setlocal + +echo ================================== +echo ACE-Step Complete Startup +echo ================================== +echo. + +REM Check if node_modules exists +if not exist "node_modules" ( + echo Error: UI dependencies not installed! + echo Please run setup.bat first. + pause + exit /b 1 +) + +if not exist "server\node_modules" ( + echo Error: Server dependencies not installed! + echo Please run setup.bat first. + pause + exit /b 1 +) + +REM Get ACE-Step path from environment or use default +if "%ACESTEP_PATH%"=="" ( + set ACESTEP_PATH=..\ACE-Step-1.5 +) + +REM Check if ACE-Step exists +if not exist "%ACESTEP_PATH%" ( + echo. + echo Warning: ACE-Step not found at %ACESTEP_PATH% + echo. + echo Please set ACESTEP_PATH or place ACE-Step-1.5 next to ace-step-ui + echo Example: set ACESTEP_PATH=C:\ACE-Step-1.5 + echo. + pause + exit /b 1 +) + +REM Detect ACE-Step installation type +set API_COMMAND= +if exist "%ACESTEP_PATH%\python_embeded\python.exe" ( + echo [+] Detected Windows Portable Package + set API_COMMAND=python_embeded\python acestep\api_server.py +) else ( + echo [+] Detected Standard Installation + set API_COMMAND=uv run acestep-api --port 8001 +) + +REM Get local IP for LAN access +for /f "tokens=2 delims=:" %%a in ('ipconfig ^| findstr /c:"IPv4"') do ( + for /f "tokens=1" %%b in ("%%a") do ( + set LOCAL_IP=%%b + ) +) + +echo. +echo ================================== +echo Starting All Services... +echo ================================== +echo. + +REM Start ACE-Step API in new window +echo [1/3] Starting ACE-Step API server... +start "ACE-Step API Server" cmd /k "cd /d "%ACESTEP_PATH%" && %API_COMMAND%" + +REM Wait for API to start +echo Waiting for API to initialize... +timeout /t 5 /nobreak >nul + +REM Start backend in new window +echo [2/3] Starting backend server... +start "ACE-Step UI Backend" cmd /k "cd /d "%~dp0server" && npm run dev" + +REM Wait for backend to start +echo Waiting for backend to start... +timeout /t 3 /nobreak >nul + +REM Start frontend in new window +echo [3/3] Starting frontend... +start "ACE-Step UI Frontend" cmd /k "cd /d "%~dp0" && npm run dev" + +REM Wait a moment +timeout /t 2 /nobreak >nul + +echo. +echo ================================== +echo All Services Running! +echo ================================== +echo. +echo ACE-Step API: http://localhost:8001 +echo Backend: http://localhost:3001 +echo Frontend: http://localhost:3000 +echo. +if defined LOCAL_IP ( + echo LAN Access: http://%LOCAL_IP%:3000 + echo. +) +echo Close the terminal windows to stop all services. +echo. +echo ================================== +echo. +echo Opening browser... +timeout /t 3 /nobreak >nul +start http://localhost:3000 + +echo. +echo Press any key to close this window (services will keep running) +pause >nul diff --git a/start-all.sh b/start-all.sh new file mode 100644 index 0000000..ba29d8c --- /dev/null +++ b/start-all.sh @@ -0,0 +1,151 @@ +#!/bin/bash +# ACE-Step UI Complete Startup Script for Linux/macOS +# Starts ACE-Step API + Backend + Frontend + +set -e + +echo "==================================" +echo " ACE-Step Complete Startup" +echo "==================================" +echo + +# Check if node_modules exists +if [ ! -d "node_modules" ]; then + echo "Error: UI dependencies not installed!" + echo "Please run ./setup.sh first." + exit 1 +fi + +if [ ! -d "server/node_modules" ]; then + echo "Error: Server dependencies not installed!" + echo "Please run ./setup.sh first." + exit 1 +fi + +# Get ACE-Step path from environment or use default +ACESTEP_PATH="${ACESTEP_PATH:-../ACE-Step-1.5}" + +# Check if ACE-Step exists +if [ ! -d "$ACESTEP_PATH" ]; then + echo + echo "Warning: ACE-Step not found at $ACESTEP_PATH" + echo + echo "Please set ACESTEP_PATH or place ACE-Step-1.5 next to ace-step-ui" + echo "Example: export ACESTEP_PATH=/path/to/ACE-Step-1.5" + echo + exit 1 +fi + +# Get local IP for LAN access +if command -v ip &> /dev/null; then + LOCAL_IP=$(ip route get 1.1.1.1 2>/dev/null | grep -oP 'src \K\S+' || echo "") +elif command -v ifconfig &> /dev/null; then + LOCAL_IP=$(ifconfig | grep "inet " | grep -v 127.0.0.1 | awk '{print $2}' | head -n1) +fi + +echo +echo "==================================" +echo " Starting All Services..." +echo "==================================" +echo + +# Create log directory +mkdir -p logs + +# Start ACE-Step API in background +echo "[1/3] Starting ACE-Step API server..." +cd "$ACESTEP_PATH" +uv run acestep-api --port 8001 > "../ace-step-ui/logs/api.log" 2>&1 & +API_PID=$! +cd - > /dev/null + +# Wait for API to start +echo "Waiting for API to initialize..." +sleep 5 + +# Check if API started successfully +if ! kill -0 $API_PID 2>/dev/null; then + echo "Error: API failed to start. Check logs/api.log" + exit 1 +fi + +# Start backend in background +echo "[2/3] Starting backend server..." +cd server +npm run dev > ../logs/backend.log 2>&1 & +BACKEND_PID=$! +cd .. + +# Wait for backend to start +echo "Waiting for backend to start..." +sleep 3 + +# Check if backend started successfully +if ! kill -0 $BACKEND_PID 2>/dev/null; then + echo "Error: Backend failed to start. Check logs/backend.log" + kill $API_PID 2>/dev/null + exit 1 +fi + +# Start frontend in background +echo "[3/3] Starting frontend..." +npm run dev > logs/frontend.log 2>&1 & +FRONTEND_PID=$! + +# Wait a moment +sleep 2 + +# Check if frontend started successfully +if ! kill -0 $FRONTEND_PID 2>/dev/null; then + echo "Error: Frontend failed to start. Check logs/frontend.log" + kill $API_PID $BACKEND_PID 2>/dev/null + exit 1 +fi + +echo +echo "==================================" +echo " All Services Running!" +echo "==================================" +echo +echo " ACE-Step API: http://localhost:8001" +echo " Backend: http://localhost:3001" +echo " Frontend: http://localhost:3000" +echo +if [ -n "$LOCAL_IP" ]; then + echo " LAN Access: http://$LOCAL_IP:3000" + echo +fi +echo " Logs: ./logs/" +echo +echo " PIDs:" +echo " API: $API_PID" +echo " Backend: $BACKEND_PID" +echo " Frontend: $FRONTEND_PID" +echo +echo "==================================" +echo + +# Save PIDs for stop script +echo "$API_PID" > logs/api.pid +echo "$BACKEND_PID" > logs/backend.pid +echo "$FRONTEND_PID" > logs/frontend.pid + +echo "Opening browser..." +sleep 3 + +# Open browser based on OS +if command -v xdg-open &> /dev/null; then + xdg-open http://localhost:3000 & +elif command -v open &> /dev/null; then + open http://localhost:3000 & +fi + +echo +echo "Services are running in background." +echo "To stop all services, run: ./stop-all.sh" +echo "Or press Ctrl+C and they will continue running." +echo + +# Wait for user interrupt +trap 'echo; echo "Services still running. Use ./stop-all.sh to stop them."; exit 0' INT +wait diff --git a/stop-all.sh b/stop-all.sh new file mode 100644 index 0000000..8137ef8 --- /dev/null +++ b/stop-all.sh @@ -0,0 +1,33 @@ +#!/bin/bash +# ACE-Step UI Stop All Services Script + +echo "Stopping all ACE-Step services..." + +if [ -f logs/api.pid ]; then + API_PID=$(cat logs/api.pid) + if kill -0 $API_PID 2>/dev/null; then + echo "Stopping API server (PID: $API_PID)..." + kill $API_PID + fi + rm logs/api.pid +fi + +if [ -f logs/backend.pid ]; then + BACKEND_PID=$(cat logs/backend.pid) + if kill -0 $BACKEND_PID 2>/dev/null; then + echo "Stopping backend (PID: $BACKEND_PID)..." + kill $BACKEND_PID + fi + rm logs/backend.pid +fi + +if [ -f logs/frontend.pid ]; then + FRONTEND_PID=$(cat logs/frontend.pid) + if kill -0 $FRONTEND_PID 2>/dev/null; then + echo "Stopping frontend (PID: $FRONTEND_PID)..." + kill $FRONTEND_PID + fi + rm logs/frontend.pid +fi + +echo "All services stopped!"