From c8c6bc5770fe2443244c5a94104d79094c99d308 Mon Sep 17 00:00:00 2001 From: akukanara Date: Sun, 31 May 2026 16:58:25 +0700 Subject: [PATCH] feat: convert python backend to a pure WebSocket API server --- README.md | 36 ++++++++++++++++++++++++------------ server.py | 46 +--------------------------------------------- start.bat | 4 ++-- 3 files changed, 27 insertions(+), 59 deletions(-) diff --git a/README.md b/README.md index 962b78d..9974a41 100644 --- a/README.md +++ b/README.md @@ -110,9 +110,10 @@ To run character models on ONNX Runtime, you must place your standard PyTorch RV --- -### 🖥️ 4. Build the Frontend (Optional) -*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`.* +### 🖥️ 4. Running the Frontend Client +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: ```bash cd frontend-next @@ -121,34 +122,45 @@ To run character models on ONNX Runtime, you must place your standard PyTorch RV ```bash 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 + 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 ``` + *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 -### Option A: Quick Launch (Windows) -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. - -### Option B: Manual CLI Execution -Run the server using your terminal: +### Step 1: Start the Python WebSocket Backend +Run the server using your terminal (defaults to port `8765`): ```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 | |---|---|---| | `--host` | The address the WebSocket server binds to. | `127.0.0.1` | | `--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` | | `--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. --- diff --git a/server.py b/server.py index 03113a6..8ab86f2 100644 --- a/server.py +++ b/server.py @@ -20,9 +20,6 @@ import logging import traceback import argparse import threading -import webbrowser -from http.server import SimpleHTTPRequestHandler -import socketserver import numpy as np import torch import onnxruntime as ort @@ -616,27 +613,7 @@ async def start_websocket_server(host, port): async with websockets.serve(websocket_handler, host, port): 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 --- 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("--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("--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("--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") @@ -731,27 +707,7 @@ if __name__ == "__main__": sys.exit(1) if args.mode == "websocket": - # 1. Start HTTP Server in a background thread to serve the frontend! - 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 + # Start the WebSocket server on the main event loop try: asyncio.run(start_websocket_server(args.host, args.port)) except KeyboardInterrupt: diff --git a/start.bat b/start.bat index 9d990f5..3c3c5b9 100644 --- a/start.bat +++ b/start.bat @@ -6,10 +6,10 @@ set VENV_PYTHON=..\rvc-tts-webui\venv\Scripts\python.exe if exist "%VENV_PYTHON%" ( 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 ( 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