feat: convert python backend to a pure WebSocket API server
This commit is contained in:
@@ -110,9 +110,10 @@ To run character models on ONNX Runtime, you must place your standard PyTorch RV
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 🖥️ 4. Build the Frontend (Optional)
|
### 🖥️ 4. Running the Frontend Client
|
||||||
*Note: Statically built files are already pre-compiled under `/frontend`. You only need to run this step if you have modified the Next.js workspace source files inside `/frontend-next`.*
|
Since the Python backend operates purely as a WebSocket API service, you must run the Next.js frontend client separately.
|
||||||
|
|
||||||
|
#### Option A: Development Server (Quick & Recommended)
|
||||||
1. Navigate to the frontend directory:
|
1. Navigate to the frontend directory:
|
||||||
```bash
|
```bash
|
||||||
cd frontend-next
|
cd frontend-next
|
||||||
@@ -121,34 +122,45 @@ To run character models on ONNX Runtime, you must place your standard PyTorch RV
|
|||||||
```bash
|
```bash
|
||||||
npm install
|
npm install
|
||||||
```
|
```
|
||||||
3. Build and export static assets (this will automatically compile files and synchronize them to the `/frontend` directory via `copy-build.js`):
|
3. Spin up the dev server:
|
||||||
```bash
|
```bash
|
||||||
|
npm run dev
|
||||||
|
```
|
||||||
|
Open your browser and navigate to **`http://localhost:3000`**.
|
||||||
|
|
||||||
|
#### Option B: Compiled Static Production Web Server
|
||||||
|
1. Navigate to `frontend-next` and build the application:
|
||||||
|
```bash
|
||||||
|
cd frontend-next
|
||||||
|
npm install
|
||||||
npm run build
|
npm run build
|
||||||
```
|
```
|
||||||
|
*Note: This will compile static pages and copy them into the root `/frontend` folder.*
|
||||||
|
2. Serve the compiled output using a static file server of your choice:
|
||||||
|
- Using Node: `npx serve ../frontend -p 3000`
|
||||||
|
- Using Python: `python -m http.server 3000 --directory ../frontend`
|
||||||
|
Open **`http://localhost:3000`** in your browser.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🏃 Running the Voice Changer
|
## 🏃 Running the Voice Changer
|
||||||
|
|
||||||
### Option A: Quick Launch (Windows)
|
### Step 1: Start the Python WebSocket Backend
|
||||||
Double-click the [start.bat](file:///M:/Users/ahmad/project/onnx-voice-changer/start.bat) file at the root. It automatically activates the Python virtual environment and fires up the server.
|
Run the server using your terminal (defaults to port `8765`):
|
||||||
|
|
||||||
### Option B: Manual CLI Execution
|
|
||||||
Run the server using your terminal:
|
|
||||||
```bash
|
```bash
|
||||||
python server.py --host 127.0.0.1 --port 8765 --http_port 8000 --device cuda
|
python server.py --host 127.0.0.1 --port 8765 --device cuda
|
||||||
```
|
```
|
||||||
|
|
||||||
### ⚙️ Command-Line Arguments
|
#### ⚙️ Command-Line Arguments
|
||||||
| Argument | Description | Default |
|
| Argument | Description | Default |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `--host` | The address the WebSocket server binds to. | `127.0.0.1` |
|
| `--host` | The address the WebSocket server binds to. | `127.0.0.1` |
|
||||||
| `--port` | WebSocket communication port. | `8765` |
|
| `--port` | WebSocket communication port. | `8765` |
|
||||||
| `--http_port`| Port serving the static frontend Web UI. | `8000` |
|
|
||||||
| `--device` | The ONNX Runtime execution device (`cpu`, `cuda`, `dml`). | `cuda` |
|
| `--device` | The ONNX Runtime execution device (`cpu`, `cuda`, `dml`). | `cuda` |
|
||||||
| `--model` | Target folder name in `weights/` to load directly upon startup. | `None` |
|
| `--model` | Target folder name in `weights/` to load directly upon startup. | `None` |
|
||||||
|
|
||||||
Once started, the application will automatically launch your browser and direct you to the premium audio dashboard at `http://localhost:8000`.
|
### Step 2: Open the Frontend Dashboard
|
||||||
|
Make sure your frontend client is running (via `npm run dev` or a static server on `http://localhost:3000`), open it in your browser, and it will automatically connect to the WebSocket API backend.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -20,9 +20,6 @@ import logging
|
|||||||
import traceback
|
import traceback
|
||||||
import argparse
|
import argparse
|
||||||
import threading
|
import threading
|
||||||
import webbrowser
|
|
||||||
from http.server import SimpleHTTPRequestHandler
|
|
||||||
import socketserver
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import torch
|
import torch
|
||||||
import onnxruntime as ort
|
import onnxruntime as ort
|
||||||
@@ -616,27 +613,7 @@ async def start_websocket_server(host, port):
|
|||||||
async with websockets.serve(websocket_handler, host, port):
|
async with websockets.serve(websocket_handler, host, port):
|
||||||
await asyncio.Future()
|
await asyncio.Future()
|
||||||
|
|
||||||
# --- HTTP STATIC FILE SERVER FOR FRONTEND ---
|
|
||||||
def start_http_server(port, directory="frontend"):
|
|
||||||
class MyHandler(SimpleHTTPRequestHandler):
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
# Force serve from directory relative to the project root
|
|
||||||
base_dir = os.path.dirname(os.path.abspath(__file__))
|
|
||||||
full_dir = os.path.join(base_dir, directory)
|
|
||||||
super().__init__(*args, directory=full_dir, **kwargs)
|
|
||||||
|
|
||||||
def log_message(self, format, *args):
|
|
||||||
# Suppress standard logging to prevent console pollution
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Create a TCPServer that allows address reuse
|
|
||||||
socketserver.TCPServer.allow_reuse_address = True
|
|
||||||
with socketserver.TCPServer(("", port), MyHandler) as httpd:
|
|
||||||
logger.info(f"Serving HTTP frontend on http://localhost:{port}")
|
|
||||||
httpd.serve_forever()
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Failed to start HTTP server: {e}")
|
|
||||||
|
|
||||||
# --- LOCAL AUDIO DEVICE STREAM MODE ---
|
# --- LOCAL AUDIO DEVICE STREAM MODE ---
|
||||||
def run_local_device_mode(model_name, f0_up_key, f0_method, device, input_device, output_device, chunk_size):
|
def run_local_device_mode(model_name, f0_up_key, f0_method, device, input_device, output_device, chunk_size):
|
||||||
@@ -709,7 +686,6 @@ if __name__ == "__main__":
|
|||||||
parser.add_argument("--mode", type=str, default="websocket", choices=["websocket", "device"], help="Server running mode")
|
parser.add_argument("--mode", type=str, default="websocket", choices=["websocket", "device"], help="Server running mode")
|
||||||
parser.add_argument("--host", type=str, default="127.0.0.1", help="WebSocket host")
|
parser.add_argument("--host", type=str, default="127.0.0.1", help="WebSocket host")
|
||||||
parser.add_argument("--port", type=int, default=8765, help="WebSocket port")
|
parser.add_argument("--port", type=int, default=8765, help="WebSocket port")
|
||||||
parser.add_argument("--http_port", type=int, default=8000, help="HTTP static server port for Web UI")
|
|
||||||
parser.add_argument("--model", type=str, default="", help="RVC Model folder name inside weights/")
|
parser.add_argument("--model", type=str, default="", help="RVC Model folder name inside weights/")
|
||||||
parser.add_argument("--transpose", type=int, default=0, help="Pitch shift in semitones (transpose)")
|
parser.add_argument("--transpose", type=int, default=0, help="Pitch shift in semitones (transpose)")
|
||||||
parser.add_argument("--f0_method", type=str, default="pm", choices=["pm", "harvest", "dio", "rmvpe"], help="Pitch extraction method")
|
parser.add_argument("--f0_method", type=str, default="pm", choices=["pm", "harvest", "dio", "rmvpe"], help="Pitch extraction method")
|
||||||
@@ -731,27 +707,7 @@ if __name__ == "__main__":
|
|||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
if args.mode == "websocket":
|
if args.mode == "websocket":
|
||||||
# 1. Start HTTP Server in a background thread to serve the frontend!
|
# Start the WebSocket server on the main event loop
|
||||||
http_thread = threading.Thread(
|
|
||||||
target=start_http_server,
|
|
||||||
args=(args.http_port, "frontend"),
|
|
||||||
daemon=True
|
|
||||||
)
|
|
||||||
http_thread.start()
|
|
||||||
|
|
||||||
# 2. Automatically open the Web UI in the default browser!
|
|
||||||
web_ui_url = f"http://127.0.0.1:{args.http_port}"
|
|
||||||
logger.info(f"Automatically launching Web UI at {web_ui_url} in browser...")
|
|
||||||
|
|
||||||
# We give it a tiny delay to ensure the HTTP server socket is open
|
|
||||||
def open_browser():
|
|
||||||
time.sleep(0.5)
|
|
||||||
webbrowser.open(web_ui_url)
|
|
||||||
|
|
||||||
browser_thread = threading.Thread(target=open_browser, daemon=True)
|
|
||||||
browser_thread.start()
|
|
||||||
|
|
||||||
# 3. Start the WebSocket server on the main event loop
|
|
||||||
try:
|
try:
|
||||||
asyncio.run(start_websocket_server(args.host, args.port))
|
asyncio.run(start_websocket_server(args.host, args.port))
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ set VENV_PYTHON=..\rvc-tts-webui\venv\Scripts\python.exe
|
|||||||
|
|
||||||
if exist "%VENV_PYTHON%" (
|
if exist "%VENV_PYTHON%" (
|
||||||
echo Menjalankan menggunakan virtual environment dari rvc-tts-webui...
|
echo Menjalankan menggunakan virtual environment dari rvc-tts-webui...
|
||||||
"%VENV_PYTHON%" -u server.py --host 127.0.0.1 --port 8765 --http_port 8000
|
"%VENV_PYTHON%" -u server.py --host 127.0.0.1 --port 8765
|
||||||
) else (
|
) else (
|
||||||
echo Virtual environment tidak ditemukan, mencoba menggunakan python sistem...
|
echo Virtual environment tidak ditemukan, mencoba menggunakan python sistem...
|
||||||
python -u server.py --host 127.0.0.1 --port 8765 --http_port 8000
|
python -u server.py --host 127.0.0.1 --port 8765
|
||||||
)
|
)
|
||||||
|
|
||||||
pause
|
pause
|
||||||
|
|||||||
Reference in New Issue
Block a user