RealTimeSTT 0.3.0__tar.gz → 0.3.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {RealtimeSTT-0.3.0/RealtimeSTT.egg-info → realtimestt-0.3.1}/PKG-INFO +149 -10
- RealtimeSTT-0.3.0/PKG-INFO → realtimestt-0.3.1/README.md +141 -29
- realtimestt-0.3.1/RealtimeSTT/__init__.py +2 -0
- {RealtimeSTT-0.3.0 → realtimestt-0.3.1}/RealtimeSTT/audio_recorder.py +39 -19
- realtimestt-0.3.1/RealtimeSTT/audio_recorder_client.py +665 -0
- RealtimeSTT-0.3.0/README.md → realtimestt-0.3.1/RealtimeSTT.egg-info/PKG-INFO +167 -3
- {RealtimeSTT-0.3.0 → realtimestt-0.3.1}/RealtimeSTT.egg-info/SOURCES.txt +7 -3
- realtimestt-0.3.1/RealtimeSTT.egg-info/entry_points.txt +3 -0
- realtimestt-0.3.1/RealtimeSTT.egg-info/requires.txt +12 -0
- {RealtimeSTT-0.3.0 → realtimestt-0.3.1}/RealtimeSTT.egg-info/top_level.txt +1 -0
- realtimestt-0.3.1/server/__init__.py +0 -0
- realtimestt-0.3.1/server/install_packages.py +105 -0
- realtimestt-0.3.1/server/stt_cli_client.py +554 -0
- realtimestt-0.3.1/server/stt_server.py +543 -0
- {RealtimeSTT-0.3.0 → realtimestt-0.3.1}/setup.py +8 -2
- RealtimeSTT-0.3.0/RealtimeSTT/__init__.py +0 -1
- RealtimeSTT-0.3.0/RealtimeSTT/outfile.py +0 -2631
- RealtimeSTT-0.3.0/RealtimeSTT/remove_comments.py +0 -78
- RealtimeSTT-0.3.0/RealtimeSTT.egg-info/requires.txt +0 -10
- {RealtimeSTT-0.3.0 → realtimestt-0.3.1}/LICENSE +0 -0
- {RealtimeSTT-0.3.0 → realtimestt-0.3.1}/RealtimeSTT.egg-info/dependency_links.txt +0 -0
- {RealtimeSTT-0.3.0 → realtimestt-0.3.1}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: RealtimeSTT
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: A fast Voice Activity Detection and Transcription System
|
|
5
5
|
Home-page: https://github.com/KoljaB/RealTimeSTT
|
|
6
6
|
Author: Kolja Beigel
|
|
@@ -15,22 +15,30 @@ License-File: LICENSE
|
|
|
15
15
|
Requires-Dist: PyAudio==0.2.14
|
|
16
16
|
Requires-Dist: faster-whisper==1.0.3
|
|
17
17
|
Requires-Dist: pvporcupine==1.9.5
|
|
18
|
-
Requires-Dist: webrtcvad==2.0.
|
|
18
|
+
Requires-Dist: webrtcvad-wheels==2.0.14
|
|
19
19
|
Requires-Dist: halo==0.0.31
|
|
20
|
-
Requires-Dist: torch
|
|
21
|
-
Requires-Dist: torchaudio
|
|
22
|
-
Requires-Dist: scipy==1.
|
|
20
|
+
Requires-Dist: torch
|
|
21
|
+
Requires-Dist: torchaudio
|
|
22
|
+
Requires-Dist: scipy==1.14.1
|
|
23
23
|
Requires-Dist: websockets==v12.0
|
|
24
|
-
Requires-Dist:
|
|
25
|
-
|
|
24
|
+
Requires-Dist: websocket-client==1.8.0
|
|
25
|
+
Requires-Dist: openwakeword>=0.4.0
|
|
26
|
+
Requires-Dist: numpy<2.0.0
|
|
26
27
|
|
|
27
28
|
# RealtimeSTT
|
|
29
|
+
[](https://pypi.org/project/RealtimeSTT/)
|
|
30
|
+
[](https://pepy.tech/project/KoljaB/RealtimeSTT)
|
|
31
|
+
[](https://GitHub.com/KoljaB/RealtimeSTT/releases/)
|
|
32
|
+
[](https://GitHub.com/Naereen/KoljaB/RealtimeSTT/commit/)
|
|
33
|
+
[](https://GitHub.com/KoljaB/RealtimeSTT/network/)
|
|
34
|
+
[](https://GitHub.com/KoljaB/RealtimeSTT/stargazers/)
|
|
28
35
|
|
|
29
36
|
*Easy-to-use, low-latency speech-to-text library for realtime applications*
|
|
30
37
|
|
|
31
38
|
## New
|
|
32
39
|
|
|
33
|
-
|
|
40
|
+
- AudioToTextRecorderClient class, which automatically starts a server if none is running and connects to it. The class shares the same interface as AudioToTextRecorder, making it easy to upgrade or switch between the two. (Work in progress, most parameters and callbacks of AudioToTextRecorder are already implemented into AudioToTextRecorderClient, but not all. Also the server can not handle concurrent (parallel) requests yet.)
|
|
41
|
+
- reworked CLI interface ("stt-server" to start the server, "stt" to start the client, look at "server" folder for more info)
|
|
34
42
|
|
|
35
43
|
## About the Project
|
|
36
44
|
|
|
@@ -47,12 +55,49 @@ https://github.com/user-attachments/assets/797e6552-27cd-41b1-a7f3-e5cbc72094f5
|
|
|
47
55
|
|
|
48
56
|
### Updates
|
|
49
57
|
|
|
50
|
-
Latest Version: v0.3.
|
|
58
|
+
Latest Version: v0.3.1
|
|
51
59
|
|
|
52
60
|
See [release history](https://github.com/KoljaB/RealtimeSTT/releases).
|
|
53
61
|
|
|
54
62
|
> **Hint:** *Since we use the `multiprocessing` module now, ensure to include the `if __name__ == '__main__':` protection in your code to prevent unexpected behavior, especially on platforms like Windows. For a detailed explanation on why this is important, visit the [official Python documentation on `multiprocessing`](https://docs.python.org/3/library/multiprocessing.html#multiprocessing-programming).*
|
|
55
63
|
|
|
64
|
+
## Quick Examples
|
|
65
|
+
|
|
66
|
+
### Print everything being said:
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
from RealtimeSTT import AudioToTextRecorder
|
|
70
|
+
import pyautogui
|
|
71
|
+
|
|
72
|
+
def process_text(text):
|
|
73
|
+
print(text)
|
|
74
|
+
|
|
75
|
+
if __name__ == '__main__':
|
|
76
|
+
print("Wait until it says 'speak now'")
|
|
77
|
+
recorder = AudioToTextRecorder()
|
|
78
|
+
|
|
79
|
+
while True:
|
|
80
|
+
recorder.text(process_text)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Type everything being said:
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
from RealtimeSTT import AudioToTextRecorder
|
|
87
|
+
import pyautogui
|
|
88
|
+
|
|
89
|
+
def process_text(text):
|
|
90
|
+
pyautogui.typewrite(text + " ")
|
|
91
|
+
|
|
92
|
+
if __name__ == '__main__':
|
|
93
|
+
print("Wait until it says 'speak now'")
|
|
94
|
+
recorder = AudioToTextRecorder()
|
|
95
|
+
|
|
96
|
+
while True:
|
|
97
|
+
recorder.text(process_text)
|
|
98
|
+
```
|
|
99
|
+
*Will type everything being said into your selected text box*
|
|
100
|
+
|
|
56
101
|
### Features
|
|
57
102
|
|
|
58
103
|
- **Voice Activity Detection**: Automatically detects when you start and stop speaking.
|
|
@@ -183,6 +228,19 @@ recorder.stop()
|
|
|
183
228
|
print(recorder.text())
|
|
184
229
|
```
|
|
185
230
|
|
|
231
|
+
#### Standalone Example:
|
|
232
|
+
|
|
233
|
+
```python
|
|
234
|
+
from RealtimeSTT import AudioToTextRecorder
|
|
235
|
+
|
|
236
|
+
if __name__ == '__main__':
|
|
237
|
+
recorder = AudioToTextRecorder()
|
|
238
|
+
recorder.start()
|
|
239
|
+
input("Press Enter to stop recording...")
|
|
240
|
+
recorder.stop()
|
|
241
|
+
print("Transcription: ", recorder.text())
|
|
242
|
+
```
|
|
243
|
+
|
|
186
244
|
### Automatic Recording
|
|
187
245
|
|
|
188
246
|
Recording based on voice activity detection.
|
|
@@ -192,8 +250,19 @@ with AudioToTextRecorder() as recorder:
|
|
|
192
250
|
print(recorder.text())
|
|
193
251
|
```
|
|
194
252
|
|
|
253
|
+
#### Standalone Example:
|
|
254
|
+
|
|
255
|
+
```python
|
|
256
|
+
from RealtimeSTT import AudioToTextRecorder
|
|
257
|
+
|
|
258
|
+
if __name__ == '__main__':
|
|
259
|
+
with AudioToTextRecorder() as recorder:
|
|
260
|
+
print("Transcription: ", recorder.text())
|
|
261
|
+
```
|
|
262
|
+
|
|
195
263
|
When running recorder.text in a loop it is recommended to use a callback, allowing the transcription to be run asynchronously:
|
|
196
264
|
|
|
265
|
+
|
|
197
266
|
```python
|
|
198
267
|
def process_text(text):
|
|
199
268
|
print (text)
|
|
@@ -202,6 +271,21 @@ while True:
|
|
|
202
271
|
recorder.text(process_text)
|
|
203
272
|
```
|
|
204
273
|
|
|
274
|
+
#### Standalone Example:
|
|
275
|
+
|
|
276
|
+
```python
|
|
277
|
+
from RealtimeSTT import AudioToTextRecorder
|
|
278
|
+
|
|
279
|
+
def process_text(text):
|
|
280
|
+
print(text)
|
|
281
|
+
|
|
282
|
+
if __name__ == '__main__':
|
|
283
|
+
recorder = AudioToTextRecorder()
|
|
284
|
+
|
|
285
|
+
while True:
|
|
286
|
+
recorder.text(process_text)
|
|
287
|
+
```
|
|
288
|
+
|
|
205
289
|
### Wakewords
|
|
206
290
|
|
|
207
291
|
Keyword activation before detecting voice. Write the comma-separated list of your desired activation keywords into the wake_words parameter. You can choose wake words from these list: alexa, americano, blueberry, bumblebee, computer, grapefruits, grasshopper, hey google, hey siri, jarvis, ok google, picovoice, porcupine, terminator.
|
|
@@ -213,6 +297,18 @@ print('Say "Jarvis" then speak.')
|
|
|
213
297
|
print(recorder.text())
|
|
214
298
|
```
|
|
215
299
|
|
|
300
|
+
#### Standalone Example:
|
|
301
|
+
|
|
302
|
+
```python
|
|
303
|
+
from RealtimeSTT import AudioToTextRecorder
|
|
304
|
+
|
|
305
|
+
if __name__ == '__main__':
|
|
306
|
+
recorder = AudioToTextRecorder(wake_words="jarvis")
|
|
307
|
+
|
|
308
|
+
print('Say "Jarvis" to start recording.')
|
|
309
|
+
print(recorder.text())
|
|
310
|
+
```
|
|
311
|
+
|
|
216
312
|
### Callbacks
|
|
217
313
|
|
|
218
314
|
You can set callback functions to be executed on different events (see [Configuration](#configuration)) :
|
|
@@ -228,6 +324,22 @@ recorder = AudioToTextRecorder(on_recording_start=my_start_callback,
|
|
|
228
324
|
on_recording_stop=my_stop_callback)
|
|
229
325
|
```
|
|
230
326
|
|
|
327
|
+
#### Standalone Example:
|
|
328
|
+
|
|
329
|
+
```python
|
|
330
|
+
from RealtimeSTT import AudioToTextRecorder
|
|
331
|
+
|
|
332
|
+
def start_callback():
|
|
333
|
+
print("Recording started!")
|
|
334
|
+
|
|
335
|
+
def stop_callback():
|
|
336
|
+
print("Recording stopped!")
|
|
337
|
+
|
|
338
|
+
if __name__ == '__main__':
|
|
339
|
+
recorder = AudioToTextRecorder(on_recording_start=start_callback,
|
|
340
|
+
on_recording_stop=stop_callback)
|
|
341
|
+
```
|
|
342
|
+
|
|
231
343
|
### Feed chunks
|
|
232
344
|
|
|
233
345
|
If you don't want to use the local microphone set use_microphone parameter to false and provide raw PCM audiochunks in 16-bit mono (samplerate 16000) with this method:
|
|
@@ -236,6 +348,20 @@ If you don't want to use the local microphone set use_microphone parameter to fa
|
|
|
236
348
|
recorder.feed_audio(audio_chunk)
|
|
237
349
|
```
|
|
238
350
|
|
|
351
|
+
#### Standalone Example:
|
|
352
|
+
|
|
353
|
+
```python
|
|
354
|
+
from RealtimeSTT import AudioToTextRecorder
|
|
355
|
+
|
|
356
|
+
if __name__ == '__main__':
|
|
357
|
+
recorder = AudioToTextRecorder(use_microphone=False)
|
|
358
|
+
with open("audio_chunk.pcm", "rb") as f:
|
|
359
|
+
audio_chunk = f.read()
|
|
360
|
+
|
|
361
|
+
recorder.feed_audio(audio_chunk)
|
|
362
|
+
print("Transcription: ", recorder.text())
|
|
363
|
+
```
|
|
364
|
+
|
|
239
365
|
### Shutdown
|
|
240
366
|
|
|
241
367
|
You can shutdown the recorder safely by using the context manager protocol:
|
|
@@ -245,12 +371,25 @@ with AudioToTextRecorder() as recorder:
|
|
|
245
371
|
[...]
|
|
246
372
|
```
|
|
247
373
|
|
|
374
|
+
|
|
248
375
|
Or you can call the shutdown method manually (if using "with" is not feasible):
|
|
249
376
|
|
|
250
377
|
```python
|
|
251
378
|
recorder.shutdown()
|
|
252
379
|
```
|
|
253
380
|
|
|
381
|
+
#### Standalone Example:
|
|
382
|
+
|
|
383
|
+
```python
|
|
384
|
+
from RealtimeSTT import AudioToTextRecorder
|
|
385
|
+
|
|
386
|
+
if __name__ == '__main__':
|
|
387
|
+
with AudioToTextRecorder() as recorder:
|
|
388
|
+
[...]
|
|
389
|
+
# or manually shutdown if "with" is not used
|
|
390
|
+
recorder.shutdown()
|
|
391
|
+
```
|
|
392
|
+
|
|
254
393
|
## Testing the Library
|
|
255
394
|
|
|
256
395
|
The test subdirectory contains a set of scripts to help you evaluate and understand the capabilities of the RealtimeTTS library.
|
|
@@ -445,7 +584,7 @@ Shoutout to [Steven Linn](https://github.com/stevenlafl) for providing docker su
|
|
|
445
584
|
|
|
446
585
|
## License
|
|
447
586
|
|
|
448
|
-
MIT
|
|
587
|
+
[MIT](https://github.com/KoljaB/RealtimeSTT?tab=MIT-1-ov-file)
|
|
449
588
|
|
|
450
589
|
## Author
|
|
451
590
|
|
|
@@ -1,36 +1,17 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: RealtimeSTT
|
|
3
|
-
Version: 0.3.0
|
|
4
|
-
Summary: A fast Voice Activity Detection and Transcription System
|
|
5
|
-
Home-page: https://github.com/KoljaB/RealTimeSTT
|
|
6
|
-
Author: Kolja Beigel
|
|
7
|
-
Author-email: kolja.beigel@web.de
|
|
8
|
-
Keywords: real-time,audio,transcription,speech-to-text,voice-activity-detection,VAD,real-time-transcription,ambient-noise-detection,microphone-input,faster_whisper,speech-recognition,voice-assistants,audio-processing,buffered-transcription,pyaudio,ambient-noise-level,voice-deactivity
|
|
9
|
-
Classifier: Programming Language :: Python :: 3
|
|
10
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
-
Classifier: Operating System :: OS Independent
|
|
12
|
-
Requires-Python: >=3.6
|
|
13
|
-
Description-Content-Type: text/markdown
|
|
14
|
-
License-File: LICENSE
|
|
15
|
-
Requires-Dist: PyAudio==0.2.14
|
|
16
|
-
Requires-Dist: faster-whisper==1.0.3
|
|
17
|
-
Requires-Dist: pvporcupine==1.9.5
|
|
18
|
-
Requires-Dist: webrtcvad==2.0.10
|
|
19
|
-
Requires-Dist: halo==0.0.31
|
|
20
|
-
Requires-Dist: torch==2.3.1
|
|
21
|
-
Requires-Dist: torchaudio==2.3.1
|
|
22
|
-
Requires-Dist: scipy==1.12.0
|
|
23
|
-
Requires-Dist: websockets==v12.0
|
|
24
|
-
Requires-Dist: openwakeword==0.6.0
|
|
25
|
-
|
|
26
|
-
|
|
27
1
|
# RealtimeSTT
|
|
2
|
+
[](https://pypi.org/project/RealtimeSTT/)
|
|
3
|
+
[](https://pepy.tech/project/KoljaB/RealtimeSTT)
|
|
4
|
+
[](https://GitHub.com/KoljaB/RealtimeSTT/releases/)
|
|
5
|
+
[](https://GitHub.com/Naereen/KoljaB/RealtimeSTT/commit/)
|
|
6
|
+
[](https://GitHub.com/KoljaB/RealtimeSTT/network/)
|
|
7
|
+
[](https://GitHub.com/KoljaB/RealtimeSTT/stargazers/)
|
|
28
8
|
|
|
29
9
|
*Easy-to-use, low-latency speech-to-text library for realtime applications*
|
|
30
10
|
|
|
31
11
|
## New
|
|
32
12
|
|
|
33
|
-
|
|
13
|
+
- AudioToTextRecorderClient class, which automatically starts a server if none is running and connects to it. The class shares the same interface as AudioToTextRecorder, making it easy to upgrade or switch between the two. (Work in progress, most parameters and callbacks of AudioToTextRecorder are already implemented into AudioToTextRecorderClient, but not all. Also the server can not handle concurrent (parallel) requests yet.)
|
|
14
|
+
- reworked CLI interface ("stt-server" to start the server, "stt" to start the client, look at "server" folder for more info)
|
|
34
15
|
|
|
35
16
|
## About the Project
|
|
36
17
|
|
|
@@ -47,12 +28,49 @@ https://github.com/user-attachments/assets/797e6552-27cd-41b1-a7f3-e5cbc72094f5
|
|
|
47
28
|
|
|
48
29
|
### Updates
|
|
49
30
|
|
|
50
|
-
Latest Version: v0.3.
|
|
31
|
+
Latest Version: v0.3.1
|
|
51
32
|
|
|
52
33
|
See [release history](https://github.com/KoljaB/RealtimeSTT/releases).
|
|
53
34
|
|
|
54
35
|
> **Hint:** *Since we use the `multiprocessing` module now, ensure to include the `if __name__ == '__main__':` protection in your code to prevent unexpected behavior, especially on platforms like Windows. For a detailed explanation on why this is important, visit the [official Python documentation on `multiprocessing`](https://docs.python.org/3/library/multiprocessing.html#multiprocessing-programming).*
|
|
55
36
|
|
|
37
|
+
## Quick Examples
|
|
38
|
+
|
|
39
|
+
### Print everything being said:
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
from RealtimeSTT import AudioToTextRecorder
|
|
43
|
+
import pyautogui
|
|
44
|
+
|
|
45
|
+
def process_text(text):
|
|
46
|
+
print(text)
|
|
47
|
+
|
|
48
|
+
if __name__ == '__main__':
|
|
49
|
+
print("Wait until it says 'speak now'")
|
|
50
|
+
recorder = AudioToTextRecorder()
|
|
51
|
+
|
|
52
|
+
while True:
|
|
53
|
+
recorder.text(process_text)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Type everything being said:
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
from RealtimeSTT import AudioToTextRecorder
|
|
60
|
+
import pyautogui
|
|
61
|
+
|
|
62
|
+
def process_text(text):
|
|
63
|
+
pyautogui.typewrite(text + " ")
|
|
64
|
+
|
|
65
|
+
if __name__ == '__main__':
|
|
66
|
+
print("Wait until it says 'speak now'")
|
|
67
|
+
recorder = AudioToTextRecorder()
|
|
68
|
+
|
|
69
|
+
while True:
|
|
70
|
+
recorder.text(process_text)
|
|
71
|
+
```
|
|
72
|
+
*Will type everything being said into your selected text box*
|
|
73
|
+
|
|
56
74
|
### Features
|
|
57
75
|
|
|
58
76
|
- **Voice Activity Detection**: Automatically detects when you start and stop speaking.
|
|
@@ -183,6 +201,19 @@ recorder.stop()
|
|
|
183
201
|
print(recorder.text())
|
|
184
202
|
```
|
|
185
203
|
|
|
204
|
+
#### Standalone Example:
|
|
205
|
+
|
|
206
|
+
```python
|
|
207
|
+
from RealtimeSTT import AudioToTextRecorder
|
|
208
|
+
|
|
209
|
+
if __name__ == '__main__':
|
|
210
|
+
recorder = AudioToTextRecorder()
|
|
211
|
+
recorder.start()
|
|
212
|
+
input("Press Enter to stop recording...")
|
|
213
|
+
recorder.stop()
|
|
214
|
+
print("Transcription: ", recorder.text())
|
|
215
|
+
```
|
|
216
|
+
|
|
186
217
|
### Automatic Recording
|
|
187
218
|
|
|
188
219
|
Recording based on voice activity detection.
|
|
@@ -192,8 +223,19 @@ with AudioToTextRecorder() as recorder:
|
|
|
192
223
|
print(recorder.text())
|
|
193
224
|
```
|
|
194
225
|
|
|
226
|
+
#### Standalone Example:
|
|
227
|
+
|
|
228
|
+
```python
|
|
229
|
+
from RealtimeSTT import AudioToTextRecorder
|
|
230
|
+
|
|
231
|
+
if __name__ == '__main__':
|
|
232
|
+
with AudioToTextRecorder() as recorder:
|
|
233
|
+
print("Transcription: ", recorder.text())
|
|
234
|
+
```
|
|
235
|
+
|
|
195
236
|
When running recorder.text in a loop it is recommended to use a callback, allowing the transcription to be run asynchronously:
|
|
196
237
|
|
|
238
|
+
|
|
197
239
|
```python
|
|
198
240
|
def process_text(text):
|
|
199
241
|
print (text)
|
|
@@ -202,6 +244,21 @@ while True:
|
|
|
202
244
|
recorder.text(process_text)
|
|
203
245
|
```
|
|
204
246
|
|
|
247
|
+
#### Standalone Example:
|
|
248
|
+
|
|
249
|
+
```python
|
|
250
|
+
from RealtimeSTT import AudioToTextRecorder
|
|
251
|
+
|
|
252
|
+
def process_text(text):
|
|
253
|
+
print(text)
|
|
254
|
+
|
|
255
|
+
if __name__ == '__main__':
|
|
256
|
+
recorder = AudioToTextRecorder()
|
|
257
|
+
|
|
258
|
+
while True:
|
|
259
|
+
recorder.text(process_text)
|
|
260
|
+
```
|
|
261
|
+
|
|
205
262
|
### Wakewords
|
|
206
263
|
|
|
207
264
|
Keyword activation before detecting voice. Write the comma-separated list of your desired activation keywords into the wake_words parameter. You can choose wake words from these list: alexa, americano, blueberry, bumblebee, computer, grapefruits, grasshopper, hey google, hey siri, jarvis, ok google, picovoice, porcupine, terminator.
|
|
@@ -213,6 +270,18 @@ print('Say "Jarvis" then speak.')
|
|
|
213
270
|
print(recorder.text())
|
|
214
271
|
```
|
|
215
272
|
|
|
273
|
+
#### Standalone Example:
|
|
274
|
+
|
|
275
|
+
```python
|
|
276
|
+
from RealtimeSTT import AudioToTextRecorder
|
|
277
|
+
|
|
278
|
+
if __name__ == '__main__':
|
|
279
|
+
recorder = AudioToTextRecorder(wake_words="jarvis")
|
|
280
|
+
|
|
281
|
+
print('Say "Jarvis" to start recording.')
|
|
282
|
+
print(recorder.text())
|
|
283
|
+
```
|
|
284
|
+
|
|
216
285
|
### Callbacks
|
|
217
286
|
|
|
218
287
|
You can set callback functions to be executed on different events (see [Configuration](#configuration)) :
|
|
@@ -228,6 +297,22 @@ recorder = AudioToTextRecorder(on_recording_start=my_start_callback,
|
|
|
228
297
|
on_recording_stop=my_stop_callback)
|
|
229
298
|
```
|
|
230
299
|
|
|
300
|
+
#### Standalone Example:
|
|
301
|
+
|
|
302
|
+
```python
|
|
303
|
+
from RealtimeSTT import AudioToTextRecorder
|
|
304
|
+
|
|
305
|
+
def start_callback():
|
|
306
|
+
print("Recording started!")
|
|
307
|
+
|
|
308
|
+
def stop_callback():
|
|
309
|
+
print("Recording stopped!")
|
|
310
|
+
|
|
311
|
+
if __name__ == '__main__':
|
|
312
|
+
recorder = AudioToTextRecorder(on_recording_start=start_callback,
|
|
313
|
+
on_recording_stop=stop_callback)
|
|
314
|
+
```
|
|
315
|
+
|
|
231
316
|
### Feed chunks
|
|
232
317
|
|
|
233
318
|
If you don't want to use the local microphone set use_microphone parameter to false and provide raw PCM audiochunks in 16-bit mono (samplerate 16000) with this method:
|
|
@@ -236,6 +321,20 @@ If you don't want to use the local microphone set use_microphone parameter to fa
|
|
|
236
321
|
recorder.feed_audio(audio_chunk)
|
|
237
322
|
```
|
|
238
323
|
|
|
324
|
+
#### Standalone Example:
|
|
325
|
+
|
|
326
|
+
```python
|
|
327
|
+
from RealtimeSTT import AudioToTextRecorder
|
|
328
|
+
|
|
329
|
+
if __name__ == '__main__':
|
|
330
|
+
recorder = AudioToTextRecorder(use_microphone=False)
|
|
331
|
+
with open("audio_chunk.pcm", "rb") as f:
|
|
332
|
+
audio_chunk = f.read()
|
|
333
|
+
|
|
334
|
+
recorder.feed_audio(audio_chunk)
|
|
335
|
+
print("Transcription: ", recorder.text())
|
|
336
|
+
```
|
|
337
|
+
|
|
239
338
|
### Shutdown
|
|
240
339
|
|
|
241
340
|
You can shutdown the recorder safely by using the context manager protocol:
|
|
@@ -245,12 +344,25 @@ with AudioToTextRecorder() as recorder:
|
|
|
245
344
|
[...]
|
|
246
345
|
```
|
|
247
346
|
|
|
347
|
+
|
|
248
348
|
Or you can call the shutdown method manually (if using "with" is not feasible):
|
|
249
349
|
|
|
250
350
|
```python
|
|
251
351
|
recorder.shutdown()
|
|
252
352
|
```
|
|
253
353
|
|
|
354
|
+
#### Standalone Example:
|
|
355
|
+
|
|
356
|
+
```python
|
|
357
|
+
from RealtimeSTT import AudioToTextRecorder
|
|
358
|
+
|
|
359
|
+
if __name__ == '__main__':
|
|
360
|
+
with AudioToTextRecorder() as recorder:
|
|
361
|
+
[...]
|
|
362
|
+
# or manually shutdown if "with" is not used
|
|
363
|
+
recorder.shutdown()
|
|
364
|
+
```
|
|
365
|
+
|
|
254
366
|
## Testing the Library
|
|
255
367
|
|
|
256
368
|
The test subdirectory contains a set of scripts to help you evaluate and understand the capabilities of the RealtimeTTS library.
|
|
@@ -445,7 +557,7 @@ Shoutout to [Steven Linn](https://github.com/stevenlafl) for providing docker su
|
|
|
445
557
|
|
|
446
558
|
## License
|
|
447
559
|
|
|
448
|
-
MIT
|
|
560
|
+
[MIT](https://github.com/KoljaB/RealtimeSTT?tab=MIT-1-ov-file)
|
|
449
561
|
|
|
450
562
|
## Author
|
|
451
563
|
|
|
@@ -29,7 +29,6 @@ Author: Kolja Beigel
|
|
|
29
29
|
from typing import Iterable, List, Optional, Union
|
|
30
30
|
import torch.multiprocessing as mp
|
|
31
31
|
import torch
|
|
32
|
-
from typing import List, Union
|
|
33
32
|
from ctypes import c_bool
|
|
34
33
|
from openwakeword.model import Model
|
|
35
34
|
from scipy.signal import resample
|
|
@@ -49,6 +48,7 @@ import platform
|
|
|
49
48
|
import pyaudio
|
|
50
49
|
import logging
|
|
51
50
|
import struct
|
|
51
|
+
import base64
|
|
52
52
|
import queue
|
|
53
53
|
import halo
|
|
54
54
|
import time
|
|
@@ -121,8 +121,9 @@ class TranscriptionWorker:
|
|
|
121
121
|
time.sleep(TIME_SLEEP)
|
|
122
122
|
|
|
123
123
|
def run(self):
|
|
124
|
-
|
|
125
|
-
|
|
124
|
+
if __name__ == "__main__":
|
|
125
|
+
system_signal.signal(system_signal.SIGINT, system_signal.SIG_IGN)
|
|
126
|
+
# __builtins__['print'] = self.custom_print
|
|
126
127
|
|
|
127
128
|
logging.info(f"Initializing faster_whisper main transcription model {self.model_path}")
|
|
128
129
|
|
|
@@ -171,7 +172,7 @@ class TranscriptionWorker:
|
|
|
171
172
|
except Exception as e:
|
|
172
173
|
logging.error(f"General error in processing queue item: {e}")
|
|
173
174
|
finally:
|
|
174
|
-
__builtins__['print'] = print # Restore the original print function
|
|
175
|
+
# __builtins__['print'] = print # Restore the original print function
|
|
175
176
|
self.conn.close()
|
|
176
177
|
self.stdout_pipe.close()
|
|
177
178
|
self.shutdown_event.set() # Ensure the polling thread will stop
|
|
@@ -539,6 +540,7 @@ class AudioToTextRecorder:
|
|
|
539
540
|
self.start_recording_event = threading.Event()
|
|
540
541
|
self.stop_recording_event = threading.Event()
|
|
541
542
|
self.last_transcription_bytes = None
|
|
543
|
+
self.last_transcription_bytes_b64 = None
|
|
542
544
|
self.initial_prompt = initial_prompt
|
|
543
545
|
self.suppress_tokens = suppress_tokens
|
|
544
546
|
self.use_wake_words = wake_words or wakeword_backend in {'oww', 'openwakeword', 'openwakewords'}
|
|
@@ -786,6 +788,10 @@ class AudioToTextRecorder:
|
|
|
786
788
|
maxlen=int((self.sample_rate // self.buffer_size) *
|
|
787
789
|
self.pre_recording_buffer_duration)
|
|
788
790
|
)
|
|
791
|
+
self.last_words_buffer = collections.deque(
|
|
792
|
+
maxlen=int((self.sample_rate // self.buffer_size) *
|
|
793
|
+
0.3)
|
|
794
|
+
)
|
|
789
795
|
self.frames = []
|
|
790
796
|
|
|
791
797
|
# Recording control flags
|
|
@@ -894,7 +900,9 @@ class AudioToTextRecorder:
|
|
|
894
900
|
import pyaudio
|
|
895
901
|
import numpy as np
|
|
896
902
|
from scipy import signal
|
|
897
|
-
|
|
903
|
+
|
|
904
|
+
if __name__ == '__main__':
|
|
905
|
+
system_signal.signal(system_signal.SIGINT, system_signal.SIG_IGN)
|
|
898
906
|
|
|
899
907
|
def get_highest_sample_rate(audio_interface, device_index):
|
|
900
908
|
"""Get the highest supported sample rate for the specified device."""
|
|
@@ -984,13 +992,16 @@ class AudioToTextRecorder:
|
|
|
984
992
|
stream = initialize_audio_stream(audio_interface, input_device_index, device_sample_rate, chunk_size)
|
|
985
993
|
if stream is not None:
|
|
986
994
|
logging.debug(f"Audio recording initialized successfully at {device_sample_rate} Hz, reading {chunk_size} frames at a time")
|
|
995
|
+
# logging.error(f"Audio recording initialized successfully at {device_sample_rate} Hz, reading {chunk_size} frames at a time")
|
|
987
996
|
return True
|
|
988
997
|
except Exception as e:
|
|
989
|
-
logging.warning(f"Failed to initialize
|
|
998
|
+
logging.warning(f"Failed to initialize audio23 stream at {device_sample_rate} Hz: {e}")
|
|
990
999
|
continue
|
|
1000
|
+
|
|
1001
|
+
|
|
991
1002
|
|
|
992
1003
|
# If we reach here, none of the sample rates worked
|
|
993
|
-
raise Exception("Failed to initialize audio
|
|
1004
|
+
raise Exception("Failed to initialize audio stream12 with all sample rates.")
|
|
994
1005
|
|
|
995
1006
|
except Exception as e:
|
|
996
1007
|
logging.exception(f"Error initializing pyaudio audio recording: {e}")
|
|
@@ -1198,7 +1209,7 @@ class AudioToTextRecorder:
|
|
|
1198
1209
|
if self.transcribe_count == 0:
|
|
1199
1210
|
logging.debug("Adding transcription request, no early transcription started")
|
|
1200
1211
|
start_time = time.time() # Start timing
|
|
1201
|
-
self.parent_transcription_pipe.send((
|
|
1212
|
+
self.parent_transcription_pipe.send((audio_copy, self.language))
|
|
1202
1213
|
self.transcribe_count += 1
|
|
1203
1214
|
|
|
1204
1215
|
while self.transcribe_count > 0:
|
|
@@ -1212,7 +1223,8 @@ class AudioToTextRecorder:
|
|
|
1212
1223
|
segments, info = result
|
|
1213
1224
|
self.detected_language = info.language if info.language_probability > 0 else None
|
|
1214
1225
|
self.detected_language_probability = info.language_probability
|
|
1215
|
-
self.last_transcription_bytes = audio_copy
|
|
1226
|
+
self.last_transcription_bytes = copy.deepcopy(audio_copy)
|
|
1227
|
+
self.last_transcription_bytes_b64 = base64.b64encode(self.last_transcription_bytes.tobytes()).decode('utf-8')
|
|
1216
1228
|
transcription = self._preprocess_output(segments)
|
|
1217
1229
|
end_time = time.time() # End timing
|
|
1218
1230
|
transcription_time = end_time - start_time
|
|
@@ -1377,6 +1389,17 @@ class AudioToTextRecorder:
|
|
|
1377
1389
|
|
|
1378
1390
|
return self
|
|
1379
1391
|
|
|
1392
|
+
def listen(self):
|
|
1393
|
+
"""
|
|
1394
|
+
Puts recorder in immediate "listen" state.
|
|
1395
|
+
This is the state after a wake word detection, for example.
|
|
1396
|
+
The recorder now "listens" for voice activation.
|
|
1397
|
+
Once voice is detected we enter "recording" state.
|
|
1398
|
+
"""
|
|
1399
|
+
self.listen_start = time.time()
|
|
1400
|
+
self._set_state("listening")
|
|
1401
|
+
self.start_recording_on_voice_activity = True
|
|
1402
|
+
|
|
1380
1403
|
def feed_audio(self, chunk, original_sample_rate=16000):
|
|
1381
1404
|
"""
|
|
1382
1405
|
Feed an audio chunk into the processing pipeline. Chunks are
|
|
@@ -1453,14 +1476,14 @@ class AudioToTextRecorder:
|
|
|
1453
1476
|
logging.debug('Terminating reader process')
|
|
1454
1477
|
|
|
1455
1478
|
# Give it some time to finish the loop and cleanup.
|
|
1456
|
-
if self.use_microphone:
|
|
1479
|
+
if self.use_microphone.value:
|
|
1457
1480
|
self.reader_process.join(timeout=10)
|
|
1458
1481
|
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1482
|
+
if self.reader_process.is_alive():
|
|
1483
|
+
logging.warning("Reader process did not terminate "
|
|
1484
|
+
"in time. Terminating forcefully."
|
|
1485
|
+
)
|
|
1486
|
+
self.reader_process.terminate()
|
|
1464
1487
|
|
|
1465
1488
|
logging.debug('Terminating transcription process')
|
|
1466
1489
|
self.transcript_process.join(timeout=10)
|
|
@@ -1521,6 +1544,7 @@ class AudioToTextRecorder:
|
|
|
1521
1544
|
logging.debug('Debug: Trying to get data from audio queue')
|
|
1522
1545
|
try:
|
|
1523
1546
|
data = self.audio_queue.get(timeout=0.01)
|
|
1547
|
+
self.last_words_buffer.append(data)
|
|
1524
1548
|
except queue.Empty:
|
|
1525
1549
|
if self.use_extended_logging:
|
|
1526
1550
|
logging.debug('Debug: Queue is empty, checking if still running')
|
|
@@ -1818,10 +1842,6 @@ class AudioToTextRecorder:
|
|
|
1818
1842
|
|
|
1819
1843
|
if self.use_extended_logging:
|
|
1820
1844
|
logging.debug('Debug: Handling non-wake word scenario')
|
|
1821
|
-
if not self.use_wake_words:
|
|
1822
|
-
self.listen_start = time.time()
|
|
1823
|
-
self._set_state("listening")
|
|
1824
|
-
self.start_recording_on_voice_activity = True
|
|
1825
1845
|
else:
|
|
1826
1846
|
if self.use_extended_logging:
|
|
1827
1847
|
logging.debug('Debug: Setting failed_stop_attempt to True')
|