|
1 | | -# FunASR-Client |
| 1 | +# Python FunASR-Client |
| 2 | + |
| 3 | +[](https://github.com/atomiechen/FunASR-Client) |
| 4 | +[](https://pypi.org/project/funasr-client/) |
| 5 | + |
| 6 | + |
| 7 | +Really easy-to-use Python client for [FunASR][1] runtime server. |
| 8 | + |
| 9 | +To deploy your own FunASR server, follow the [FunASR runtime guide][2], or use the improved startup scripts [here][3]. |
| 10 | + |
| 11 | +## Features |
| 12 | + |
| 13 | +- ☯️ Both synchronous and asynchronous (`async`) support everywhere |
| 14 | +- 💻 Both Command Line Interface (CLI) and Python API |
| 15 | +- 🔤 Auto decoding of messages with real timestamps (`FunASRMessageDecoded`) |
| 16 | +- 🎙️ Real-time audio recognition from a microphone (`mic_asr`) |
| 17 | +- 🎵 File-based audio recognition (`file_asr`) |
| 18 | + |
| 19 | + |
| 20 | +## Installation |
| 21 | + |
| 22 | +Install directly from PyPI: |
| 23 | + |
| 24 | +```bash |
| 25 | +pip install funasr-client |
| 26 | +``` |
| 27 | + |
| 28 | +If you want to use the microphone (`pyaudio`) for real-time recognition, install with: |
| 29 | + |
| 30 | +```bash |
| 31 | +pip install "funasr-client[mic]" |
| 32 | +``` |
| 33 | + |
| 34 | +Install from github for the latest updates: |
| 35 | + |
| 36 | +```bash |
| 37 | +pip install "git+https://github.com/atomiechen/FunASR-Client.git" |
| 38 | +``` |
| 39 | + |
| 40 | +## CLI |
| 41 | + |
| 42 | +The CLI supports either real-time microphone input or file input for ASR, and outputs the recognized results in JSON (file) or JSON Lines (mic) format. |
| 43 | + |
| 44 | + |
| 45 | +<details> |
| 46 | +<summary>View all CLI options by running <code>funasr-client -h</code>.</summary> |
| 47 | + |
| 48 | +``` |
| 49 | +usage: funasr-client [-h] [-v] [--mode MODE] [--chunk_size P C F] [--chunk_interval CHUNK_INTERVAL] [--audio_fs AUDIO_FS] |
| 50 | + [--hotwords WORD:WEIGHT [WORD:WEIGHT ...]] [--no-itn] [--svs_lang SVS_LANG] [--no-svs_itn] [--async] |
| 51 | + URI [FILE_PATH] |
| 52 | +
|
| 53 | +FunASR Client CLI v0.1.0. Use microphone for real-time recognition (needs pyaudio), or specify input audio file. |
| 54 | +
|
| 55 | +positional arguments: |
| 56 | + URI WebSocket URI to connect to the FunASR server. |
| 57 | + FILE_PATH Optional input audio file path (suppress microphone). (default: None) |
| 58 | +
|
| 59 | +optional arguments: |
| 60 | + -h, --help show this help message and exit |
| 61 | + -v, --version show program's version number and exit |
| 62 | + --mode MODE offline, online, 2pass (default: 2pass) |
| 63 | + --chunk_size P C F Chunk size: past, current, future. (default: [5, 10, 5]) |
| 64 | + --chunk_interval CHUNK_INTERVAL |
| 65 | + Chunk interval. (default: 10) |
| 66 | + --audio_fs AUDIO_FS Audio sampling frequency. (default: 16000) |
| 67 | + --hotwords WORD:WEIGHT [WORD:WEIGHT ...] |
| 68 | + Hotwords with weights, e.g., 'hello:10 world:5'. (default: []) |
| 69 | + --no-itn Disable ITN (default: True) |
| 70 | + --svs_lang SVS_LANG SVS language. (default: auto) |
| 71 | + --no-svs_itn Disable SVS ITN (default: True) |
| 72 | + --async Use asynchronous client. (default: False) |
| 73 | +``` |
| 74 | + |
| 75 | +</details> |
| 76 | + |
| 77 | +### Microphone Real-time ASR |
| 78 | + |
| 79 | +Requires `pyaudio` for microphone support (install it using `pip install "funasr-client[mic]"`). |
| 80 | + |
| 81 | +```sh |
| 82 | +funasr-client ws://localhost:10096 |
| 83 | +``` |
| 84 | + |
| 85 | +### File ASR |
| 86 | + |
| 87 | +```sh |
| 88 | +funasr-client ws://localhost:10096 path/to/audio.wav |
| 89 | +``` |
| 90 | + |
| 91 | + |
| 92 | +## Python API |
| 93 | + |
| 94 | +Sync API (`funasr_client`): |
| 95 | +```python |
| 96 | +from funasr_client import funasr_client |
| 97 | + |
| 98 | +with funasr_client("ws://localhost:10096") as client: |
| 99 | + @client.on_message |
| 100 | + def callback(msg): |
| 101 | + print("Received:", msg) |
| 102 | +``` |
| 103 | + |
| 104 | +Async API (`async_funasr_client`): |
| 105 | +```python |
| 106 | +from funasr_client import async_funasr_client |
| 107 | + |
| 108 | +async def main(): |
| 109 | + async with async_funasr_client("ws://localhost:10096") as client: |
| 110 | + # NOTE: sync callback is also supported |
| 111 | + @client.on_message |
| 112 | + async def callback(msg): |
| 113 | + print("Received:", msg) |
| 114 | +``` |
| 115 | + |
| 116 | +See scripts in the [examples directory](examples/) for real-world usage. |
| 117 | + |
| 118 | +### Registering Callbacks in non-blocking mode |
| 119 | + |
| 120 | +By default, the client runs in non-blocking mode, which allows you to continue using your program while waiting for ASR results. |
| 121 | +It starts a background loop in a thread (sync) or an async task (async) to handle incoming messages. |
| 122 | + |
| 123 | +Two ways to register message callbacks (**both** sync and async are supported): |
| 124 | +1. Using `@client.on_message` decorator (like shown above). |
| 125 | +2. Passing `callback` handler to the constructor. |
| 126 | + ```python |
| 127 | + funasr_client( |
| 128 | + ... |
| 129 | + callback=lambda msg: print(msg) |
| 130 | + ) |
| 131 | + ``` |
| 132 | + |
| 133 | +> [!NOTE] |
| 134 | +> Sync callback in async client will be run in a thread pool executor. |
| 135 | + |
| 136 | + |
| 137 | +### Blocking Mode |
| 138 | + |
| 139 | +To run in blocking mode (disable background loop), pass `blocking=True` to the client constructor. |
| 140 | +It is your responsibility to call `client.stream()` or `client.recv()` to receive messages. |
| 141 | + |
| 142 | +Use `client.stream()` (async) generator to receive messages in a loop: |
| 143 | + |
| 144 | +```python |
| 145 | +from funasr_client import funasr_client |
| 146 | +with funasr_client("ws://localhost:10096", blocking=True) as client: |
| 147 | + for msg in client.stream(): |
| 148 | + print("Received:", msg) |
| 149 | +``` |
| 150 | + |
| 151 | +Or, use the low-level `client.recv()` method to receive messages one by one: |
| 152 | + |
| 153 | +```python |
| 154 | +from funasr_client import funasr_client |
| 155 | +with funasr_client("ws://localhost:10096", blocking=True) as client: |
| 156 | + while True: |
| 157 | + msg = client.recv() |
| 158 | + if msg is None: |
| 159 | + break |
| 160 | + print("Received:", msg) |
| 161 | +``` |
| 162 | + |
| 163 | + |
| 164 | +### Decoding Messages |
| 165 | + |
| 166 | +By default, the client decodes response messages into `FunASRMessageDecoded` dicts, which parses `timestamps` JSON string into a list. |
| 167 | +If `start_time` (int in ms) is provided to the client, `real_timestamp` and `real_stamp_sents` will be calculated and added to the decoded message. |
| 168 | + |
| 169 | +To disable decoding, pass `decode=False` to the constructor to get original dict object. |
| 170 | + |
| 171 | + |
| 172 | +### Microphone Real-time ASR |
| 173 | + |
| 174 | +Open a microphone stream and get the stream of **decoded** messages (`mic_asr` / `async_mic_asr`): |
| 175 | + |
| 176 | +```python |
| 177 | +from funasr_client import mic_asr |
| 178 | +with mic_asr("ws://localhost:10096") as msg_gen: |
| 179 | + for msg in msg_gen: |
| 180 | + print("Received:", msg) |
| 181 | +``` |
| 182 | + |
| 183 | +### File ASR |
| 184 | + |
| 185 | +Get the final result as a **merged decoded** message (`file_asr` / `async_file_asr`): |
| 186 | + |
| 187 | +```python |
| 188 | +from funasr_client import file_asr |
| 189 | + |
| 190 | +result = file_asr("path/to/audio.wav", "ws://localhost:10096") |
| 191 | +print(result) |
| 192 | +``` |
| 193 | + |
| 194 | +Or, get the stream of **decoded or original** (depends on `decode` option) messages (`file_asr_stream` / `async_file_asr_stream`): |
| 195 | + |
| 196 | +```python |
| 197 | +from funasr_client import file_asr_stream |
| 198 | + |
| 199 | +with file_asr_stream("path/to/audio.wav", "ws://localhost:10096") as msg_gen: |
| 200 | + for msg in msg_gen: |
| 201 | + print("Received:", msg) |
| 202 | +``` |
| 203 | + |
| 204 | + |
| 205 | +[1]: https://github.com/modelscope/FunASR |
| 206 | +[2]: https://github.com/modelscope/FunASR/blob/main/runtime/readme.md |
| 207 | +[3]: https://gist.github.com/atomiechen/2deaf80dba21b4434ab21d6bf656fbca |
0 commit comments