RealTimeSTT 0.3.93__tar.gz → 0.3.94__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.
Files changed (19) hide show
  1. {realtimestt-0.3.93 → realtimestt-0.3.94}/PKG-INFO +4 -4
  2. {realtimestt-0.3.93 → realtimestt-0.3.94}/RealtimeSTT/audio_input.py +81 -14
  3. {realtimestt-0.3.93 → realtimestt-0.3.94}/RealtimeSTT/audio_recorder.py +101 -22
  4. {realtimestt-0.3.93 → realtimestt-0.3.94}/RealtimeSTT.egg-info/PKG-INFO +4 -4
  5. {realtimestt-0.3.93 → realtimestt-0.3.94}/RealtimeSTT.egg-info/requires.txt +3 -3
  6. {realtimestt-0.3.93 → realtimestt-0.3.94}/setup.py +1 -1
  7. {realtimestt-0.3.93 → realtimestt-0.3.94}/LICENSE +0 -0
  8. {realtimestt-0.3.93 → realtimestt-0.3.94}/README.md +0 -0
  9. {realtimestt-0.3.93 → realtimestt-0.3.94}/RealtimeSTT/__init__.py +0 -0
  10. {realtimestt-0.3.93 → realtimestt-0.3.94}/RealtimeSTT/audio_recorder_client.py +0 -0
  11. {realtimestt-0.3.93 → realtimestt-0.3.94}/RealtimeSTT.egg-info/SOURCES.txt +0 -0
  12. {realtimestt-0.3.93 → realtimestt-0.3.94}/RealtimeSTT.egg-info/dependency_links.txt +0 -0
  13. {realtimestt-0.3.93 → realtimestt-0.3.94}/RealtimeSTT.egg-info/entry_points.txt +0 -0
  14. {realtimestt-0.3.93 → realtimestt-0.3.94}/RealtimeSTT.egg-info/top_level.txt +0 -0
  15. {realtimestt-0.3.93 → realtimestt-0.3.94}/RealtimeSTT_server/__init__.py +0 -0
  16. {realtimestt-0.3.93 → realtimestt-0.3.94}/RealtimeSTT_server/install_packages.py +0 -0
  17. {realtimestt-0.3.93 → realtimestt-0.3.94}/RealtimeSTT_server/stt_cli_client.py +0 -0
  18. {realtimestt-0.3.93 → realtimestt-0.3.94}/RealtimeSTT_server/stt_server.py +0 -0
  19. {realtimestt-0.3.93 → realtimestt-0.3.94}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: RealtimeSTT
3
- Version: 0.3.93
3
+ Version: 0.3.94
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
@@ -13,15 +13,15 @@ Requires-Python: >=3.6
13
13
  Description-Content-Type: text/markdown
14
14
  License-File: LICENSE
15
15
  Requires-Dist: PyAudio==0.2.14
16
- Requires-Dist: faster-whisper==1.1.0
16
+ Requires-Dist: faster-whisper==1.1.1
17
17
  Requires-Dist: pvporcupine==1.9.5
18
18
  Requires-Dist: webrtcvad-wheels==2.0.14
19
19
  Requires-Dist: halo==0.0.31
20
20
  Requires-Dist: torch
21
21
  Requires-Dist: torchaudio
22
- Requires-Dist: scipy==1.14.1
22
+ Requires-Dist: scipy==1.15.1
23
23
  Requires-Dist: openwakeword>=0.4.0
24
- Requires-Dist: websockets==14.1
24
+ Requires-Dist: websockets==14.2
25
25
  Requires-Dist: websocket-client==1.8.0
26
26
  Requires-Dist: numpy<2.0.0
27
27
 
@@ -1,22 +1,35 @@
1
1
  from colorama import init, Fore, Style
2
+ from scipy.signal import butter, filtfilt, resample_poly
2
3
  import pyaudio
3
4
  import logging
4
- import time
5
5
 
6
+ DESIRED_RATE = 16000
7
+ CHUNK_SIZE = 1024
8
+ AUDIO_FORMAT = pyaudio.paInt16
9
+ CHANNELS = 1
6
10
 
7
11
  class AudioInput:
8
- def __init__(self, input_device_index=None, debug_mode=False):
12
+ def __init__(
13
+ self,
14
+ input_device_index: int = None,
15
+ debug_mode: bool = False,
16
+ target_samplerate: int = DESIRED_RATE,
17
+ chunk_size: int = CHUNK_SIZE,
18
+ audio_format: int = AUDIO_FORMAT,
19
+ channels: int = CHANNELS,
20
+ resample_to_target: bool = True,
21
+ ):
22
+
9
23
  self.input_device_index = input_device_index
10
24
  self.debug_mode = debug_mode
11
25
  self.audio_interface = None
12
26
  self.stream = None
13
27
  self.device_sample_rate = None
14
-
15
- # PyAudio constants
16
- self.CHUNK = 1024
17
- self.FORMAT = pyaudio.paInt16
18
- self.CHANNELS = 1
19
- self.DESIRED_RATE = 16000
28
+ self.target_samplerate = target_samplerate
29
+ self.chunk_size = chunk_size
30
+ self.audio_format = audio_format
31
+ self.channels = channels
32
+ self.resample_to_target = resample_to_target
20
33
 
21
34
  def get_supported_sample_rates(self, device_index):
22
35
  """Test which standard sample rates are supported by the specified device."""
@@ -31,8 +44,8 @@ class AudioInput:
31
44
  if self.audio_interface.is_format_supported(
32
45
  rate,
33
46
  input_device=device_index, # Changed to input_device
34
- input_channels=max_channels, # Changed to input_channels
35
- input_format=self.FORMAT, # Changed to input_format
47
+ input_channels=max_channels, # Changed to input_channels
48
+ input_format=self.audio_format, # Changed to input_format
36
49
  ):
37
50
  supported_rates.append(rate)
38
51
  except:
@@ -108,18 +121,18 @@ class AudioInput:
108
121
  if self.debug_mode:
109
122
  print(f"Actual selected device index: {actual_device_index}")
110
123
  self.input_device_index = actual_device_index
111
- self.device_sample_rate = self._get_best_sample_rate(actual_device_index, self.DESIRED_RATE)
124
+ self.device_sample_rate = self._get_best_sample_rate(actual_device_index, self.target_samplerate)
112
125
 
113
126
  if self.debug_mode:
114
127
  print(f"Setting up audio on device {self.input_device_index} with sample rate {self.device_sample_rate}")
115
128
 
116
129
  try:
117
130
  self.stream = self.audio_interface.open(
118
- format=self.FORMAT,
119
- channels=self.CHANNELS,
131
+ format=self.audio_format,
132
+ channels=self.channels,
120
133
  rate=self.device_sample_rate,
121
134
  input=True,
122
- frames_per_buffer=self.CHUNK,
135
+ frames_per_buffer=self.chunk_size,
123
136
  input_device_index=self.input_device_index,
124
137
  )
125
138
  if self.debug_mode:
@@ -135,6 +148,60 @@ class AudioInput:
135
148
  self.audio_interface.terminate()
136
149
  return False
137
150
 
151
+ def lowpass_filter(self, signal, cutoff_freq, sample_rate):
152
+ """
153
+ Apply a low-pass Butterworth filter to prevent aliasing in the signal.
154
+
155
+ Args:
156
+ signal (np.ndarray): Input audio signal to filter
157
+ cutoff_freq (float): Cutoff frequency in Hz
158
+ sample_rate (float): Sampling rate of the input signal in Hz
159
+
160
+ Returns:
161
+ np.ndarray: Filtered audio signal
162
+
163
+ Notes:
164
+ - Uses a 5th order Butterworth filter
165
+ - Applies zero-phase filtering using filtfilt
166
+ """
167
+ # Calculate the Nyquist frequency (half the sample rate)
168
+ nyquist_rate = sample_rate / 2.0
169
+
170
+ # Normalize cutoff frequency to Nyquist rate (required by butter())
171
+ normal_cutoff = cutoff_freq / nyquist_rate
172
+
173
+ # Design the Butterworth filter
174
+ b, a = butter(5, normal_cutoff, btype='low', analog=False)
175
+
176
+ # Apply zero-phase filtering (forward and backward)
177
+ filtered_signal = filtfilt(b, a, signal)
178
+ return filtered_signal
179
+
180
+ def resample_audio(self, pcm_data, target_sample_rate, original_sample_rate):
181
+ """
182
+ Filter and resample audio data to a target sample rate.
183
+
184
+ Args:
185
+ pcm_data (np.ndarray): Input audio data
186
+ target_sample_rate (int): Desired output sample rate in Hz
187
+ original_sample_rate (int): Original sample rate of input in Hz
188
+
189
+ Returns:
190
+ np.ndarray: Resampled audio data
191
+
192
+ Notes:
193
+ - Applies anti-aliasing filter before resampling
194
+ - Uses polyphase filtering for high-quality resampling
195
+ """
196
+ if target_sample_rate < original_sample_rate:
197
+ # Downsampling with low-pass filter
198
+ pcm_filtered = self.lowpass_filter(pcm_data, target_sample_rate / 2, original_sample_rate)
199
+ resampled = resample_poly(pcm_filtered, target_sample_rate, original_sample_rate)
200
+ else:
201
+ # Upsampling without low-pass filter
202
+ resampled = resample_poly(pcm_data, target_sample_rate, original_sample_rate)
203
+ return resampled
204
+
138
205
  def read_chunk(self):
139
206
  """Read a chunk of audio data"""
140
207
  return self.stream.read(self.CHUNK, exception_on_overflow=False)
@@ -120,7 +120,7 @@ class TranscriptionWorker:
120
120
  data = self.conn.recv()
121
121
  self.queue.put(data)
122
122
  except Exception as e:
123
- logging.error(f"Error receiving data from connection: {e}")
123
+ logging.error(f"Error receiving data from connection: {e}", exc_info=True)
124
124
  else:
125
125
  time.sleep(TIME_SLEEP)
126
126
 
@@ -162,6 +162,7 @@ class TranscriptionWorker:
162
162
  try:
163
163
  audio, language = self.queue.get(timeout=0.1)
164
164
  try:
165
+ logging.debug(f"Transcribing audio with language {language}")
165
166
  if self.batch_size > 0:
166
167
  segments, info = model.transcribe(
167
168
  audio,
@@ -184,7 +185,7 @@ class TranscriptionWorker:
184
185
  logging.debug(f"Final text detected with main model: {transcription}")
185
186
  self.conn.send(('success', (transcription, info)))
186
187
  except Exception as e:
187
- logging.error(f"General error in transcription: {e}")
188
+ logging.error(f"General error in transcription: {e}", exc_info=True)
188
189
  self.conn.send(('error', str(e)))
189
190
  except queue.Empty:
190
191
  continue
@@ -193,7 +194,7 @@ class TranscriptionWorker:
193
194
  logging.debug("Transcription worker process finished due to KeyboardInterrupt")
194
195
  break
195
196
  except Exception as e:
196
- logging.error(f"General error in processing queue item: {e}")
197
+ logging.error(f"General error in processing queue item: {e}", exc_info=True)
197
198
  finally:
198
199
  __builtins__['print'] = print # Restore the original print function
199
200
  self.conn.close()
@@ -567,6 +568,8 @@ class AudioToTextRecorder:
567
568
  self.sample_rate = sample_rate
568
569
  self.recording_start_time = 0
569
570
  self.recording_stop_time = 0
571
+ self.last_recording_start_time = 0
572
+ self.last_recording_stop_time = 0
570
573
  self.wake_word_detect_time = 0
571
574
  self.silero_check_time = 0
572
575
  self.silero_working = False
@@ -590,6 +593,8 @@ class AudioToTextRecorder:
590
593
  self.stream = None
591
594
  self.start_recording_event = threading.Event()
592
595
  self.stop_recording_event = threading.Event()
596
+ self.backdate_stop_seconds = 0.0
597
+ self.backdate_resume_seconds = 0.0
593
598
  self.last_transcription_bytes = None
594
599
  self.last_transcription_bytes_b64 = None
595
600
  self.initial_prompt = initial_prompt
@@ -860,6 +865,7 @@ class AudioToTextRecorder:
860
865
  0.3)
861
866
  )
862
867
  self.frames = []
868
+ self.last_frames = []
863
869
 
864
870
  # Recording control flags
865
871
  self.is_recording = False
@@ -925,7 +931,7 @@ class AudioToTextRecorder:
925
931
  logging.info("KeyboardInterrupt in read from stdout detected, exiting...")
926
932
  break
927
933
  except Exception as e:
928
- logging.error(f"Unexpected error in read from stdout: {e}")
934
+ logging.error(f"Unexpected error in read from stdout: {e}", exc_info=True)
929
935
  logging.error(traceback.format_exc()) # Log the full traceback here
930
936
  break
931
937
  time.sleep(0.1)
@@ -1074,7 +1080,7 @@ class AudioToTextRecorder:
1074
1080
  return stream
1075
1081
 
1076
1082
  except Exception as e:
1077
- logging.error(f"Microphone connection failed: {e}. Retrying...")
1083
+ logging.error(f"Microphone connection failed: {e}. Retrying...", exc_info=True)
1078
1084
  input_device_index = None
1079
1085
  time.sleep(3) # Wait before retrying
1080
1086
  continue
@@ -1190,7 +1196,7 @@ class AudioToTextRecorder:
1190
1196
  if e.errno == pyaudio.paInputOverflowed:
1191
1197
  logging.warning("Input overflowed. Frame dropped.")
1192
1198
  else:
1193
- logging.error(f"OSError during recording: {e}")
1199
+ logging.error(f"OSError during recording: {e}", exc_info=True)
1194
1200
  # Attempt to reinitialize the stream
1195
1201
  logging.error("Attempting to reinitialize the audio stream...")
1196
1202
 
@@ -1308,13 +1314,60 @@ class AudioToTextRecorder:
1308
1314
  if (self.stop_recording_event.wait(timeout=0.02)):
1309
1315
  break
1310
1316
 
1311
- # Convert recorded frames to the appropriate audio format.
1312
- audio_array = np.frombuffer(b''.join(self.frames), dtype=np.int16)
1313
- self.audio = audio_array.astype(np.float32) / INT16_MAX_ABS_VALUE
1317
+ frames = self.frames
1318
+ if len(frames) == 0:
1319
+ frames = self.last_frames
1320
+
1321
+ # Calculate samples needed for backdating resume
1322
+ samples_to_keep = int(self.sample_rate * self.backdate_resume_seconds)
1323
+
1324
+ # First convert all current frames to audio array
1325
+ full_audio_array = np.frombuffer(b''.join(frames), dtype=np.int16)
1326
+ full_audio = full_audio_array.astype(np.float32) / INT16_MAX_ABS_VALUE
1327
+
1328
+ # Calculate how many samples we need to keep for backdating resume
1329
+ if samples_to_keep > 0:
1330
+ samples_to_keep = min(samples_to_keep, len(full_audio))
1331
+ # Keep the last N samples for backdating resume
1332
+ frames_to_read_audio = full_audio[-samples_to_keep:]
1333
+
1334
+ # Convert the audio back to int16 bytes for frames
1335
+ frames_to_read_int16 = (frames_to_read_audio * INT16_MAX_ABS_VALUE).astype(np.int16)
1336
+ frame_bytes = frames_to_read_int16.tobytes()
1337
+
1338
+ # Split into appropriate frame sizes (assuming standard frame size)
1339
+ FRAME_SIZE = 2048 # Typical frame size
1340
+ frames_to_read = []
1341
+ for i in range(0, len(frame_bytes), FRAME_SIZE):
1342
+ frame = frame_bytes[i:i + FRAME_SIZE]
1343
+ if frame: # Only add non-empty frames
1344
+ frames_to_read.append(frame)
1345
+ else:
1346
+ frames_to_read = []
1347
+
1348
+ # Process backdate stop seconds
1349
+ samples_to_remove = int(self.sample_rate * self.backdate_stop_seconds)
1350
+
1351
+ if samples_to_remove > 0:
1352
+ if samples_to_remove < len(full_audio):
1353
+ self.audio = full_audio[:-samples_to_remove]
1354
+ logging.debug(f"Removed {samples_to_remove} samples "
1355
+ f"({samples_to_remove/self.sample_rate:.3f}s) from end of audio")
1356
+ else:
1357
+ self.audio = np.array([], dtype=np.float32)
1358
+ logging.debug("Cleared audio (samples_to_remove >= audio length)")
1359
+ else:
1360
+ self.audio = full_audio
1361
+ logging.debug(f"No samples removed, final audio length: {len(self.audio)}")
1362
+
1314
1363
  self.frames.clear()
1364
+ self.last_frames.clear()
1365
+ self.frames.extend(frames_to_read)
1366
+
1367
+ # Reset backdating parameters
1368
+ self.backdate_stop_seconds = 0.0
1369
+ self.backdate_resume_seconds = 0.0
1315
1370
 
1316
- # Reset recording-related timestamps
1317
- self.recording_stop_time = 0
1318
1371
  self.listen_start = 0
1319
1372
 
1320
1373
  self._set_state("inactive")
@@ -1388,7 +1441,7 @@ class AudioToTextRecorder:
1388
1441
  logging.error(f"Transcription error: {result}")
1389
1442
  raise Exception(result)
1390
1443
  except Exception as e:
1391
- logging.error(f"Error during transcription: {str(e)}")
1444
+ logging.error(f"Error during transcription: {str(e)}", exc_info=True)
1392
1445
  raise e
1393
1446
 
1394
1447
  def _process_wakeword(self, data):
@@ -1476,7 +1529,16 @@ class AudioToTextRecorder:
1476
1529
  return self.transcribe()
1477
1530
 
1478
1531
 
1479
- def start(self):
1532
+ def format_number(self, num):
1533
+ # Convert the number to a string
1534
+ num_str = f"{num:.10f}" # Ensure precision is sufficient
1535
+ # Split the number into integer and decimal parts
1536
+ integer_part, decimal_part = num_str.split('.')
1537
+ # Take the last two digits of the integer part and the first two digits of the decimal part
1538
+ result = f"{integer_part[-2:]}.{decimal_part[:2]}"
1539
+ return result
1540
+
1541
+ def start(self, frames = None):
1480
1542
  """
1481
1543
  Starts recording audio directly without waiting for voice activity.
1482
1544
  """
@@ -1498,7 +1560,10 @@ class AudioToTextRecorder:
1498
1560
  self.wakeword_detected = False
1499
1561
  self.wake_word_detect_time = 0
1500
1562
  self.frames = []
1563
+ if frames:
1564
+ self.frames = frames
1501
1565
  self.is_recording = True
1566
+
1502
1567
  self.recording_start_time = time.time()
1503
1568
  self.is_silero_speech_active = False
1504
1569
  self.is_webrtc_speech_active = False
@@ -1510,9 +1575,19 @@ class AudioToTextRecorder:
1510
1575
 
1511
1576
  return self
1512
1577
 
1513
- def stop(self):
1578
+ def stop(self,
1579
+ backdate_stop_seconds: float = 0.0,
1580
+ backdate_resume_seconds: float = 0.0,
1581
+ ):
1514
1582
  """
1515
1583
  Stops recording audio.
1584
+
1585
+ Args:
1586
+ - backdate_stop_seconds (float, default="0.0"): Specifies the number of
1587
+ seconds to backdate the stop time. This is useful when the stop
1588
+ command is issued after the actual stop time.
1589
+ - backdate_resume_seconds (float, default="0.0"): Specifies the number
1590
+ of seconds to backdate the time relistening is initiated.
1516
1591
  """
1517
1592
 
1518
1593
  # Ensure there's a minimum interval
@@ -1525,6 +1600,9 @@ class AudioToTextRecorder:
1525
1600
  return self
1526
1601
 
1527
1602
  logging.info("recording stopped")
1603
+ self.last_frames = copy.deepcopy(self.frames)
1604
+ self.backdate_stop_seconds = backdate_stop_seconds
1605
+ self.backdate_resume_seconds = backdate_resume_seconds
1528
1606
  self.is_recording = False
1529
1607
  self.recording_stop_time = time.time()
1530
1608
  self.is_silero_speech_active = False
@@ -1533,6 +1611,9 @@ class AudioToTextRecorder:
1533
1611
  self.start_recording_event.clear()
1534
1612
  self.stop_recording_event.set()
1535
1613
 
1614
+ self.last_recording_start_time = self.recording_start_time
1615
+ self.last_recording_stop_time = self.recording_stop_time
1616
+
1536
1617
  if self.on_recording_stop:
1537
1618
  self.on_recording_stop()
1538
1619
 
@@ -1607,7 +1688,6 @@ class AudioToTextRecorder:
1607
1688
  return
1608
1689
 
1609
1690
  print("\033[91mRealtimeSTT shutting down\033[0m")
1610
- # logging.debug("RealtimeSTT shutting down")
1611
1691
 
1612
1692
  # Force wait_audio() and text() to exit
1613
1693
  self.is_shut_down = True
@@ -1736,7 +1816,7 @@ class AudioToTextRecorder:
1736
1816
  data = self.audio_queue.get()
1737
1817
 
1738
1818
  except BrokenPipeError:
1739
- logging.error("BrokenPipeError _recording_worker")
1819
+ logging.error("BrokenPipeError _recording_worker", exc_info=True)
1740
1820
  self.is_running = False
1741
1821
  break
1742
1822
 
@@ -1813,11 +1893,11 @@ class AudioToTextRecorder:
1813
1893
 
1814
1894
  except struct.error:
1815
1895
  logging.error("Error unpacking audio data "
1816
- "for wake word processing.")
1896
+ "for wake word processing.", exc_info=True)
1817
1897
  continue
1818
1898
 
1819
1899
  except Exception as e:
1820
- logging.error(f"Wake word processing error: {e}")
1900
+ logging.error(f"Wake word processing error: {e}", exc_info=True)
1821
1901
  continue
1822
1902
 
1823
1903
  if self.use_extended_logging:
@@ -2044,7 +2124,7 @@ class AudioToTextRecorder:
2044
2124
  except Exception as e:
2045
2125
  logging.debug('Debug: Caught exception in main try block')
2046
2126
  if not self.interrupt_stop_event.is_set():
2047
- logging.error(f"Unhandled exeption in _recording_worker: {e}")
2127
+ logging.error(f"Unhandled exeption in _recording_worker: {e}", exc_info=True)
2048
2128
  raise
2049
2129
 
2050
2130
  if self.use_extended_logging:
@@ -2111,7 +2191,7 @@ class AudioToTextRecorder:
2111
2191
  logging.warning("Realtime transcription timed out")
2112
2192
  continue
2113
2193
  except Exception as e:
2114
- logging.error(f"Error in realtime transcription: {str(e)}")
2194
+ logging.error(f"Error in realtime transcription: {str(e)}", exc_info=True)
2115
2195
  continue
2116
2196
  else:
2117
2197
  # Perform transcription and assemble the text
@@ -2145,7 +2225,6 @@ class AudioToTextRecorder:
2145
2225
  if self.is_recording and time.time() - \
2146
2226
  self.recording_start_time > self.init_realtime_after_seconds:
2147
2227
 
2148
- # logging.debug('Starting realtime transcription')
2149
2228
  self.realtime_transcription_text = realtime_text
2150
2229
  self.realtime_transcription_text = \
2151
2230
  self.realtime_transcription_text.strip()
@@ -2225,7 +2304,7 @@ class AudioToTextRecorder:
2225
2304
  time.sleep(TIME_SLEEP)
2226
2305
 
2227
2306
  except Exception as e:
2228
- logging.error(f"Unhandled exeption in _realtime_worker: {e}")
2307
+ logging.error(f"Unhandled exeption in _realtime_worker: {e}", exc_info=True)
2229
2308
  raise
2230
2309
 
2231
2310
  def _is_silero_speech(self, chunk):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: RealtimeSTT
3
- Version: 0.3.93
3
+ Version: 0.3.94
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
@@ -13,15 +13,15 @@ Requires-Python: >=3.6
13
13
  Description-Content-Type: text/markdown
14
14
  License-File: LICENSE
15
15
  Requires-Dist: PyAudio==0.2.14
16
- Requires-Dist: faster-whisper==1.1.0
16
+ Requires-Dist: faster-whisper==1.1.1
17
17
  Requires-Dist: pvporcupine==1.9.5
18
18
  Requires-Dist: webrtcvad-wheels==2.0.14
19
19
  Requires-Dist: halo==0.0.31
20
20
  Requires-Dist: torch
21
21
  Requires-Dist: torchaudio
22
- Requires-Dist: scipy==1.14.1
22
+ Requires-Dist: scipy==1.15.1
23
23
  Requires-Dist: openwakeword>=0.4.0
24
- Requires-Dist: websockets==14.1
24
+ Requires-Dist: websockets==14.2
25
25
  Requires-Dist: websocket-client==1.8.0
26
26
  Requires-Dist: numpy<2.0.0
27
27
 
@@ -1,12 +1,12 @@
1
1
  PyAudio==0.2.14
2
- faster-whisper==1.1.0
2
+ faster-whisper==1.1.1
3
3
  pvporcupine==1.9.5
4
4
  webrtcvad-wheels==2.0.14
5
5
  halo==0.0.31
6
6
  torch
7
7
  torchaudio
8
- scipy==1.14.1
8
+ scipy==1.15.1
9
9
  openwakeword>=0.4.0
10
- websockets==14.1
10
+ websockets==14.2
11
11
  websocket-client==1.8.0
12
12
  numpy<2.0.0
@@ -9,7 +9,7 @@ with open('requirements.txt') as f:
9
9
 
10
10
  setuptools.setup(
11
11
  name="RealtimeSTT",
12
- version="0.3.93",
12
+ version="0.3.94",
13
13
  author="Kolja Beigel",
14
14
  author_email="kolja.beigel@web.de",
15
15
  description="A fast Voice Activity Detection and Transcription System",
File without changes
File without changes
File without changes