update CLI launch
Browse files- README.md +65 -56
- setup.py +1 -1
- whisperlivekit/basic_server.py +86 -0
- whisperlivekit/core.py +4 -1
README.md
CHANGED
@@ -26,7 +26,7 @@ This project is based on [Whisper Streaming](https://github.com/ufal/whisper_str
|
|
26 |
|
27 |
## Installation
|
28 |
|
29 |
-
### Via pip
|
30 |
|
31 |
```bash
|
32 |
pip install whisperlivekit
|
@@ -46,67 +46,75 @@ pip install whisperlivekit
|
|
46 |
|
47 |
You need to install FFmpeg on your system:
|
48 |
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
- Install required Python dependencies:
|
63 |
-
|
64 |
-
```bash
|
65 |
-
# Whisper streaming required dependencies
|
66 |
-
pip install librosa soundfile
|
67 |
-
|
68 |
-
# Whisper streaming web required dependencies
|
69 |
-
pip install fastapi ffmpeg-python
|
70 |
-
```
|
71 |
-
- Install at least one whisper backend among:
|
72 |
-
|
73 |
-
```
|
74 |
-
whisper
|
75 |
-
whisper-timestamped
|
76 |
-
faster-whisper (faster backend on NVIDIA GPU)
|
77 |
-
mlx-whisper (faster backend on Apple Silicon)
|
78 |
-
```
|
79 |
-
- Optionnal dependencies
|
80 |
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
|
|
|
|
|
|
89 |
|
90 |
-
|
91 |
-
uvicorn
|
92 |
|
93 |
-
|
94 |
-
diart
|
95 |
-
```
|
96 |
|
97 |
-
|
98 |
|
|
|
99 |
|
100 |
-
|
|
|
|
|
101 |
|
102 |
-
|
103 |
-
|
104 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
105 |
|
106 |
-
**Parameters**
|
107 |
-
|
108 |
-
The following parameters are supported:
|
109 |
-
|
110 |
- `--host` and `--port` let you specify the server's IP/port.
|
111 |
- `-min-chunk-size` sets the minimum chunk size for audio processing. Make sure this value aligns with the chunk size selected in the frontend. If not aligned, the system will work but may unnecessarily over-process audio data.
|
112 |
- `--transcription`: Enable/disable transcription (default: True)
|
@@ -135,12 +143,13 @@ You need to install FFmpeg on your system:
|
|
135 |
- Open your browser at `http://localhost:8000` (or replace `localhost` and `8000` with whatever you specified).
|
136 |
- The page uses vanilla JavaScript and the WebSocket API to capture your microphone and stream audio to the server in real time.
|
137 |
|
138 |
-
|
|
|
139 |
|
140 |
- Once you **allow microphone access**, the page records small chunks of audio using the **MediaRecorder** API in **webm/opus** format.
|
141 |
- These chunks are sent over a **WebSocket** to the FastAPI endpoint at `/asr`.
|
142 |
- The Python server decodes `.webm` chunks on the fly using **FFmpeg** and streams them into the **whisper streaming** implementation for transcription.
|
143 |
-
- **Partial transcription** appears as soon as enough audio is processed. The
|
144 |
- You can watch the transcription update in near real time, ideal for demos, prototyping, or quick debugging.
|
145 |
|
146 |
### Deploying to a Remote Server
|
@@ -155,4 +164,4 @@ No additional front-end libraries or frameworks are required. The WebSocket logi
|
|
155 |
|
156 |
## Acknowledgments
|
157 |
|
158 |
-
This project builds upon the foundational work of the Whisper Streaming project. We extend our gratitude to the original authors for their contributions.
|
|
|
26 |
|
27 |
## Installation
|
28 |
|
29 |
+
### Via pip (recommended)
|
30 |
|
31 |
```bash
|
32 |
pip install whisperlivekit
|
|
|
46 |
|
47 |
You need to install FFmpeg on your system:
|
48 |
|
49 |
+
```bash
|
50 |
+
# For Ubuntu/Debian:
|
51 |
+
sudo apt install ffmpeg
|
52 |
+
|
53 |
+
# For macOS:
|
54 |
+
brew install ffmpeg
|
55 |
+
|
56 |
+
# For Windows:
|
57 |
+
# Download from https://ffmpeg.org/download.html and add to PATH
|
58 |
+
```
|
59 |
+
|
60 |
+
### Optional Dependencies
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
61 |
|
62 |
+
```bash
|
63 |
+
# If you want to use VAC (Voice Activity Controller). Useful for preventing hallucinations
|
64 |
+
pip install torch
|
65 |
|
66 |
+
# If you choose sentences as buffer trimming strategy
|
67 |
+
pip install mosestokenizer wtpsplit
|
68 |
+
pip install tokenize_uk # If you work with Ukrainian text
|
69 |
+
|
70 |
+
# If you want to use diarization
|
71 |
+
pip install diart
|
72 |
+
```
|
73 |
|
74 |
+
Diart uses [pyannote.audio](https://github.com/pyannote/pyannote-audio) models from the _huggingface hub_. To use them, please follow the steps described [here](https://github.com/juanmc2005/diart?tab=readme-ov-file#get-access-to--pyannote-models).
|
|
|
75 |
|
76 |
+
## Usage
|
|
|
|
|
77 |
|
78 |
+
### Using the command-line tool
|
79 |
|
80 |
+
After installation, you can start the server using the provided command-line tool:
|
81 |
|
82 |
+
```bash
|
83 |
+
whisperlivekit-server --host 0.0.0.0 --port 8000 --model tiny.en
|
84 |
+
```
|
85 |
|
86 |
+
Then open your browser at `http://localhost:8000` (or your specified host and port).
|
87 |
+
|
88 |
+
### Using the library in your code
|
89 |
+
|
90 |
+
```python
|
91 |
+
from whisperlivekit import WhisperLiveKit
|
92 |
+
from fastapi import FastAPI, WebSocket
|
93 |
+
|
94 |
+
# Initialize WhisperLiveKit with custom parameters
|
95 |
+
kit = WhisperLiveKit(
|
96 |
+
model="tiny.en",
|
97 |
+
diarization=True,
|
98 |
+
)
|
99 |
+
|
100 |
+
# Create a FastAPI application
|
101 |
+
app = FastAPI()
|
102 |
+
|
103 |
+
@app.get("/")
|
104 |
+
async def get():
|
105 |
+
# Use the built-in web interface
|
106 |
+
return HTMLResponse(kit.web_interface())
|
107 |
+
|
108 |
+
# Your websocket endpoints for audio processing...
|
109 |
+
```
|
110 |
+
|
111 |
+
For a complete audio processing example, check [whisper_fastapi_online_server.py](https://github.com/QuentinFuxa/WhisperLiveKit/blob/main/whisper_fastapi_online_server.py)
|
112 |
+
|
113 |
+
|
114 |
+
## Configuration Options
|
115 |
+
|
116 |
+
The following parameters are supported when initializing `WhisperLiveKit`:
|
117 |
|
|
|
|
|
|
|
|
|
118 |
- `--host` and `--port` let you specify the server's IP/port.
|
119 |
- `-min-chunk-size` sets the minimum chunk size for audio processing. Make sure this value aligns with the chunk size selected in the frontend. If not aligned, the system will work but may unnecessarily over-process audio data.
|
120 |
- `--transcription`: Enable/disable transcription (default: True)
|
|
|
143 |
- Open your browser at `http://localhost:8000` (or replace `localhost` and `8000` with whatever you specified).
|
144 |
- The page uses vanilla JavaScript and the WebSocket API to capture your microphone and stream audio to the server in real time.
|
145 |
|
146 |
+
|
147 |
+
## How the Live Interface Works
|
148 |
|
149 |
- Once you **allow microphone access**, the page records small chunks of audio using the **MediaRecorder** API in **webm/opus** format.
|
150 |
- These chunks are sent over a **WebSocket** to the FastAPI endpoint at `/asr`.
|
151 |
- The Python server decodes `.webm` chunks on the fly using **FFmpeg** and streams them into the **whisper streaming** implementation for transcription.
|
152 |
+
- **Partial transcription** appears as soon as enough audio is processed. The "unvalidated" text is shown in **lighter or grey color** (i.e., an 'aperçu') to indicate it's still buffered partial output. Once Whisper finalizes that segment, it's displayed in normal text.
|
153 |
- You can watch the transcription update in near real time, ideal for demos, prototyping, or quick debugging.
|
154 |
|
155 |
### Deploying to a Remote Server
|
|
|
164 |
|
165 |
## Acknowledgments
|
166 |
|
167 |
+
This project builds upon the foundational work of the Whisper Streaming project. We extend our gratitude to the original authors for their contributions.
|
setup.py
CHANGED
@@ -28,7 +28,7 @@ setup(
|
|
28 |
},
|
29 |
entry_points={
|
30 |
'console_scripts': [
|
31 |
-
'whisperlivekit-server=whisperlivekit.
|
32 |
],
|
33 |
},
|
34 |
classifiers=[
|
|
|
28 |
},
|
29 |
entry_points={
|
30 |
'console_scripts': [
|
31 |
+
'whisperlivekit-server=whisperlivekit.basic_server:main',
|
32 |
],
|
33 |
},
|
34 |
classifiers=[
|
whisperlivekit/basic_server.py
ADDED
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from contextlib import asynccontextmanager
|
2 |
+
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
|
3 |
+
from fastapi.responses import HTMLResponse
|
4 |
+
from fastapi.middleware.cors import CORSMiddleware
|
5 |
+
|
6 |
+
from whisperlivekit import WhisperLiveKit
|
7 |
+
from whisperlivekit.audio_processor import AudioProcessor
|
8 |
+
|
9 |
+
import asyncio
|
10 |
+
import logging
|
11 |
+
import os
|
12 |
+
|
13 |
+
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
|
14 |
+
logging.getLogger().setLevel(logging.WARNING)
|
15 |
+
logger = logging.getLogger(__name__)
|
16 |
+
logger.setLevel(logging.DEBUG)
|
17 |
+
|
18 |
+
kit = None
|
19 |
+
|
20 |
+
@asynccontextmanager
|
21 |
+
async def lifespan(app: FastAPI):
|
22 |
+
global kit
|
23 |
+
kit = WhisperLiveKit()
|
24 |
+
yield
|
25 |
+
|
26 |
+
app = FastAPI(lifespan=lifespan)
|
27 |
+
app.add_middleware(
|
28 |
+
CORSMiddleware,
|
29 |
+
allow_origins=["*"],
|
30 |
+
allow_credentials=True,
|
31 |
+
allow_methods=["*"],
|
32 |
+
allow_headers=["*"],
|
33 |
+
)
|
34 |
+
|
35 |
+
|
36 |
+
@app.get("/")
|
37 |
+
async def get():
|
38 |
+
return HTMLResponse(kit.web_interface())
|
39 |
+
|
40 |
+
|
41 |
+
async def handle_websocket_results(websocket, results_generator):
|
42 |
+
"""Consumes results from the audio processor and sends them via WebSocket."""
|
43 |
+
try:
|
44 |
+
async for response in results_generator:
|
45 |
+
await websocket.send_json(response)
|
46 |
+
except Exception as e:
|
47 |
+
logger.warning(f"Error in WebSocket results handler: {e}")
|
48 |
+
|
49 |
+
|
50 |
+
@app.websocket("/asr")
|
51 |
+
async def websocket_endpoint(websocket: WebSocket):
|
52 |
+
audio_processor = AudioProcessor()
|
53 |
+
|
54 |
+
await websocket.accept()
|
55 |
+
logger.info("WebSocket connection opened.")
|
56 |
+
|
57 |
+
results_generator = await audio_processor.create_tasks()
|
58 |
+
websocket_task = asyncio.create_task(handle_websocket_results(websocket, results_generator))
|
59 |
+
|
60 |
+
try:
|
61 |
+
while True:
|
62 |
+
message = await websocket.receive_bytes()
|
63 |
+
await audio_processor.process_audio(message)
|
64 |
+
except WebSocketDisconnect:
|
65 |
+
logger.warning("WebSocket disconnected.")
|
66 |
+
finally:
|
67 |
+
websocket_task.cancel()
|
68 |
+
await audio_processor.cleanup()
|
69 |
+
logger.info("WebSocket endpoint cleaned up.")
|
70 |
+
|
71 |
+
def main():
|
72 |
+
"""Entry point for the CLI command."""
|
73 |
+
import uvicorn
|
74 |
+
|
75 |
+
temp_kit = WhisperLiveKit(transcription=False, diarization=False)
|
76 |
+
|
77 |
+
uvicorn.run(
|
78 |
+
"whisperlivekit.basic_server:app",
|
79 |
+
host=temp_kit.args.host,
|
80 |
+
port=temp_kit.args.port,
|
81 |
+
reload=True,
|
82 |
+
log_level="info"
|
83 |
+
)
|
84 |
+
|
85 |
+
if __name__ == "__main__":
|
86 |
+
main()
|
whisperlivekit/core.py
CHANGED
@@ -1,4 +1,7 @@
|
|
1 |
-
|
|
|
|
|
|
|
2 |
from argparse import Namespace, ArgumentParser
|
3 |
|
4 |
def parse_args():
|
|
|
1 |
+
try:
|
2 |
+
from whisperlivekit.whisper_streaming_custom.whisper_online import backend_factory, warmup_asr
|
3 |
+
except:
|
4 |
+
from whisper_streaming_custom.whisper_online import backend_factory, warmup_asr
|
5 |
from argparse import Namespace, ArgumentParser
|
6 |
|
7 |
def parse_args():
|