Merge remote-tracking branch 'upstream/main' into vad_warnings
This commit is contained in:
+169
-13
@@ -18,12 +18,13 @@ def resample(file: str, sr: int = 16000):
|
||||
# https://github.com/openai/whisper/blob/7858aa9c08d98f75575035ecd6481f462d66ca27/whisper/audio.py#L22
|
||||
Open an audio file and read as mono waveform, resampling as necessary,
|
||||
save the resampled audio
|
||||
Parameters
|
||||
----------
|
||||
file: str
|
||||
The audio file to open
|
||||
sr: int
|
||||
The sample rate to resample the audio if necessary
|
||||
|
||||
Args:
|
||||
file (str): The audio file to open
|
||||
sr (int): The sample rate to resample the audio if necessary
|
||||
|
||||
Returns:
|
||||
resampled_file (str): The resampled audio file
|
||||
"""
|
||||
try:
|
||||
# This launches a subprocess to decode audio while down-mixing and resampling as necessary.
|
||||
@@ -43,11 +44,28 @@ def resample(file: str, sr: int = 16000):
|
||||
|
||||
|
||||
class Client:
|
||||
"""
|
||||
Handles audio recording, streaming, and communication with a server using WebSocket.
|
||||
"""
|
||||
INSTANCES = {}
|
||||
|
||||
def __init__(
|
||||
self, host=None, port=None, is_multilingual=False, lang=None, translate=False
|
||||
):
|
||||
"""
|
||||
Initializes a Client instance for audio recording and streaming to a server.
|
||||
|
||||
If host and port are not provided, the WebSocket connection will not be established.
|
||||
When translate is True, the task will be set to "translate" instead of "transcribe".
|
||||
he audio recording starts immediately upon initialization.
|
||||
|
||||
Args:
|
||||
host (str): The hostname or IP address of the server.
|
||||
port (int): The port number for the WebSocket server.
|
||||
is_multilingual (bool, optional): Specifies if multilingual transcription is enabled. Default is False.
|
||||
lang (str, optional): The selected language for transcription when multilingual is disabled. Default is None.
|
||||
translate (bool, optional): Specifies if the task is translation. Default is False.
|
||||
"""
|
||||
self.chunk = 1024
|
||||
self.format = pyaudio.paInt16
|
||||
self.channels = 1
|
||||
@@ -77,7 +95,6 @@ class Client:
|
||||
frames_per_buffer=self.chunk,
|
||||
)
|
||||
|
||||
# create websocket connection
|
||||
if host is not None and port is not None:
|
||||
socket_url = f"ws://{host}:{port}"
|
||||
self.client_socket = websocket.WebSocketApp(
|
||||
@@ -104,6 +121,18 @@ class Client:
|
||||
print("[INFO]: * recording")
|
||||
|
||||
def on_message(self, ws, message):
|
||||
"""
|
||||
Callback function called when a message is received from the server.
|
||||
|
||||
It updates various attributes of the client based on the received message, including
|
||||
recording status, language detection, and server messages. If a disconnect message
|
||||
is received, it sets the recording status to False.
|
||||
|
||||
Args:
|
||||
ws (websocket.WebSocketApp): The WebSocket client instance.
|
||||
message (str): The received message from the server.
|
||||
|
||||
"""
|
||||
self.last_response_recieved = time.time()
|
||||
message = json.loads(message)
|
||||
|
||||
@@ -164,6 +193,16 @@ class Client:
|
||||
print(f"[INFO]: Websocket connection closed: {close_status_code}: {close_msg}")
|
||||
|
||||
def on_open(self, ws):
|
||||
"""
|
||||
Callback function called when the WebSocket connection is successfully opened.
|
||||
|
||||
Sends an initial configuration message to the server, including client UID, multilingual mode,
|
||||
language selection, and task type.
|
||||
|
||||
Args:
|
||||
ws (websocket.WebSocketApp): The WebSocket client instance.
|
||||
|
||||
"""
|
||||
print(self.multilingual, self.language, self.task)
|
||||
|
||||
print("[INFO]: Opened connection")
|
||||
@@ -180,16 +219,49 @@ class Client:
|
||||
|
||||
@staticmethod
|
||||
def bytes_to_float_array(audio_bytes):
|
||||
"""
|
||||
Convert audio data from bytes to a NumPy float array.
|
||||
|
||||
It assumes that the audio data is in 16-bit PCM format. The audio data is normalized to
|
||||
have values between -1 and 1.
|
||||
|
||||
Args:
|
||||
audio_bytes (bytes): Audio data in bytes.
|
||||
|
||||
Returns:
|
||||
np.ndarray: A NumPy array containing the audio data as float values normalized between -1 and 1.
|
||||
"""
|
||||
raw_data = np.frombuffer(buffer=audio_bytes, dtype=np.int16)
|
||||
return raw_data.astype(np.float32) / 32768.0
|
||||
|
||||
def send_packet_to_server(self, message):
|
||||
"""
|
||||
Send an audio packet to the server using WebSocket.
|
||||
|
||||
Args:
|
||||
message (bytes): The audio data packet in bytes to be sent to the server.
|
||||
|
||||
"""
|
||||
try:
|
||||
self.client_socket.send(message, websocket.ABNF.OPCODE_BINARY)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
def play_file(self, filename):
|
||||
"""
|
||||
Play an audio file and send it to the server for processing.
|
||||
|
||||
Reads an audio file, plays it through the audio output, and simultaneously sends
|
||||
the audio data to the server for processing. It uses PyAudio to create an audio
|
||||
stream for playback. The audio data is read from the file in chunks, converted to
|
||||
floating-point format, and sent to the server using WebSocket communication.
|
||||
This method is typically used when you want to process pre-recorded audio and send it
|
||||
to the server in real-time.
|
||||
|
||||
Args:
|
||||
filename (str): The path to the audio file to be played and sent to the server.
|
||||
"""
|
||||
|
||||
# read audio and create pyaudio stream
|
||||
with wave.open(filename, "rb") as wavfile:
|
||||
self.stream = self.p.open(
|
||||
@@ -213,8 +285,7 @@ class Client:
|
||||
wavfile.close()
|
||||
|
||||
assert self.last_response_recieved
|
||||
elapsed_time = time.time() - self.last_response_recieved
|
||||
while elapsed_time < self.disconnect_if_no_response_for:
|
||||
while time.time() - self.last_response_recieved < self.disconnect_if_no_response_for:
|
||||
continue
|
||||
self.stream.close()
|
||||
self.close_websocket()
|
||||
@@ -228,20 +299,44 @@ class Client:
|
||||
print("[INFO]: Keyboard interrupt.")
|
||||
|
||||
def close_websocket(self):
|
||||
"""
|
||||
Close the WebSocket connection and join the WebSocket thread.
|
||||
|
||||
First attempts to close the WebSocket connection using `self.client_socket.close()`. After
|
||||
closing the connection, it joins the WebSocket thread to ensure proper termination.
|
||||
|
||||
"""
|
||||
try:
|
||||
self.client_socket.close() # Close the WebSocket connection
|
||||
self.client_socket.close()
|
||||
except Exception as e:
|
||||
print("[ERROR]: Error closing WebSocket:", e)
|
||||
|
||||
try:
|
||||
self.ws_thread.join() # Wait for the WebSocket thread to finish
|
||||
self.ws_thread.join()
|
||||
except Exception as e:
|
||||
print("[ERROR:] Error joining WebSocket thread:", e)
|
||||
|
||||
def get_client_socket(self):
|
||||
"""
|
||||
Get the WebSocket client socket instance.
|
||||
|
||||
Returns:
|
||||
WebSocketApp: The WebSocket client socket instance currently in use by the client.
|
||||
"""
|
||||
return self.client_socket
|
||||
|
||||
def write_audio_frames_to_file(self, frames, file_name):
|
||||
"""
|
||||
Write audio frames to a WAV file.
|
||||
|
||||
The WAV file is created or overwritten with the specified name. The audio frames should be
|
||||
in the correct format and match the specified channel, sample width, and sample rate.
|
||||
|
||||
Args:
|
||||
frames (bytes): The audio frames to be written to the file.
|
||||
file_name (str): The name of the WAV file to which the frames will be written.
|
||||
|
||||
"""
|
||||
with wave.open(file_name, "wb") as wavfile:
|
||||
wavfile: wave.Wave_write
|
||||
wavfile.setnchannels(self.channels)
|
||||
@@ -250,8 +345,23 @@ class Client:
|
||||
wavfile.writeframes(frames)
|
||||
|
||||
def record(self, out_file="output_recording.wav"):
|
||||
"""
|
||||
Record audio data from the input stream and save it to a WAV file.
|
||||
|
||||
Continuously records audio data from the input stream, sends it to the server via a WebSocket
|
||||
connection, and simultaneously saves it to multiple WAV files in chunks. It stops recording when
|
||||
the `RECORD_SECONDS` duration is reached or when the `RECORDING` flag is set to `False`.
|
||||
|
||||
Audio data is saved in chunks to the "chunks" directory. Each chunk is saved as a separate WAV file.
|
||||
The recording will continue until the specified duration is reached or until the `RECORDING` flag is set to `False`.
|
||||
The recording process can be interrupted by sending a KeyboardInterrupt (e.g., pressing Ctrl+C). After recording,
|
||||
the method combines all the saved audio chunks into the specified `out_file`.
|
||||
|
||||
Args:
|
||||
out_file (str, optional): The name of the output WAV file to save the entire recording. Default is "output_recording.wav".
|
||||
|
||||
"""
|
||||
n_audio_file = 0
|
||||
# create dir for saving audio chunks
|
||||
if not os.path.exists("chunks"):
|
||||
os.makedirs("chunks", exist_ok=True)
|
||||
try:
|
||||
@@ -289,10 +399,22 @@ class Client:
|
||||
self.p.terminate()
|
||||
self.close_websocket()
|
||||
|
||||
# combine all the audio files
|
||||
self.write_output_recording(n_audio_file, out_file)
|
||||
|
||||
def write_output_recording(self, n_audio_file, out_file):
|
||||
"""
|
||||
Combine and save recorded audio chunks into a single WAV file.
|
||||
|
||||
The individual audio chunk files are expected to be located in the "chunks" directory. Reads each chunk
|
||||
file, appends its audio data to the final recording, and then deletes the chunk file. After combining
|
||||
and saving, the final recording is stored in the specified `out_file`.
|
||||
|
||||
|
||||
Args:
|
||||
n_audio_file (int): The number of audio chunk files to combine.
|
||||
out_file (str): The name of the output WAV file to save the final recording.
|
||||
|
||||
"""
|
||||
input_files = [
|
||||
f"chunks/{i}.wav"
|
||||
for i in range(n_audio_file)
|
||||
@@ -316,10 +438,44 @@ class Client:
|
||||
|
||||
|
||||
class TranscriptionClient:
|
||||
"""
|
||||
Client for handling audio transcription tasks via a WebSocket connection.
|
||||
|
||||
Acts as a high-level client for audio transcription tasks using a WebSocket connection. It can be used
|
||||
to send audio data for transcription to a server and receive transcribed text segments.
|
||||
|
||||
Args:
|
||||
host (str): The hostname or IP address of the server.
|
||||
port (int): The port number to connect to on the server.
|
||||
is_multilingual (bool, optional): Indicates whether the transcription should support multiple languages (default is False).
|
||||
lang (str, optional): The primary language for transcription (used if `is_multilingual` is False). Default is None, which defaults to English ('en').
|
||||
translate (bool, optional): Indicates whether translation tasks are required (default is False).
|
||||
|
||||
Attributes:
|
||||
client (Client): An instance of the underlying Client class responsible for handling the WebSocket connection.
|
||||
|
||||
Example:
|
||||
To create a TranscriptionClient and start transcription on microphone audio:
|
||||
```python
|
||||
transcription_client = TranscriptionClient(host="localhost", port=9090, is_multilingual=True)
|
||||
transcription_client()
|
||||
```
|
||||
"""
|
||||
def __init__(self, host, port, is_multilingual=False, lang=None, translate=False):
|
||||
self.client = Client(host, port, is_multilingual, lang, translate)
|
||||
|
||||
def __call__(self, audio=None):
|
||||
"""
|
||||
Start the transcription process.
|
||||
|
||||
Initiates the transcription process by connecting to the server via a WebSocket. It waits for the server
|
||||
to be ready to receive audio data and then sends audio for transcription. If an audio file is provided, it
|
||||
will be played and streamed to the server; otherwise, it will perform live recording.
|
||||
|
||||
Args:
|
||||
audio (str, optional): Path to an audio file for transcription. Default is None, which triggers live recording.
|
||||
|
||||
"""
|
||||
print("[INFO]: Waiting for server ready ...")
|
||||
while not self.client.recording:
|
||||
if self.client.waiting:
|
||||
|
||||
+154
-26
@@ -1,16 +1,12 @@
|
||||
import websockets
|
||||
import pickle, struct, time, pyaudio
|
||||
import time
|
||||
import threading
|
||||
import os, json
|
||||
import base64
|
||||
import wave
|
||||
import json
|
||||
import textwrap
|
||||
|
||||
import logging
|
||||
# logging.basicConfig(level = logging.INFO)
|
||||
|
||||
from collections import deque
|
||||
from dataclasses import dataclass
|
||||
from websockets.sync.server import serve
|
||||
|
||||
import torch
|
||||
@@ -25,35 +21,66 @@ class TranscriptionServer:
|
||||
Represents a transcription server that handles incoming audio from clients.
|
||||
|
||||
Attributes:
|
||||
RATE (int): The audio sampling rate (constant) set to 16000.
|
||||
vad_model (torch.Module): The voice activity detection model.
|
||||
vad_threshold (float): The voice activity detection threshold.
|
||||
clients (dict): A dictionary to store connected clients.
|
||||
websockets (dict): A dictionary to store WebSocket connections.
|
||||
clients_start_time (dict): A dictionary to track client start times.
|
||||
max_clients (int): Maximum allowed connected clients.
|
||||
max_connection_time (int): Maximum allowed connection time in seconds.
|
||||
"""
|
||||
|
||||
RATE = 16000
|
||||
|
||||
def __init__(self):
|
||||
# voice activity detection model
|
||||
self.vad_model = VoiceActivityDetection()
|
||||
self.vad_threshold = 0.4
|
||||
|
||||
self.clients = {}
|
||||
self.websockets = {}
|
||||
self.clients_start_time = {}
|
||||
self.max_clients = 4
|
||||
self.max_connection_time = 600 # in seconds
|
||||
|
||||
self.max_connection_time = 600
|
||||
|
||||
def get_wait_time(self):
|
||||
"""
|
||||
Calculate and return the estimated wait time for clients.
|
||||
|
||||
Returns:
|
||||
float: The estimated wait time in minutes.
|
||||
"""
|
||||
wait_time = None
|
||||
for k,v in self.clients_start_time.items():
|
||||
|
||||
for k, v in self.clients_start_time.items():
|
||||
current_client_time_remaining = self.max_connection_time - (time.time() - v)
|
||||
if wait_time is None:
|
||||
|
||||
if wait_time is None or current_client_time_remaining < wait_time:
|
||||
wait_time = current_client_time_remaining
|
||||
elif current_client_time_remaining < wait_time:
|
||||
wait_time = current_client_time_remaining
|
||||
return wait_time/60
|
||||
|
||||
return wait_time / 60
|
||||
|
||||
def recv_audio(self, websocket):
|
||||
"""
|
||||
Receive audio chunks from a client in an infinite loop.
|
||||
|
||||
Continuously receives audio frames from a connected client
|
||||
over a WebSocket connection. It processes the audio frames using a
|
||||
voice activity detection (VAD) model to determine if they contain speech
|
||||
or not. If the audio frame contains speech, it is added to the client's
|
||||
audio data for ASR.
|
||||
If the maximum number of clients is reached, the method sends a
|
||||
"WAIT" status to the client, indicating that they should wait
|
||||
until a slot is available.
|
||||
If a client's connection exceeds the maximum allowed time, it will
|
||||
be disconnected, and the client's resources will be cleaned up.
|
||||
|
||||
Args:
|
||||
websocket (WebSocket): The WebSocket connection for the client.
|
||||
|
||||
Raises:
|
||||
Exception: If there is an error during the audio frame processing.
|
||||
"""
|
||||
logging.info("New client connected")
|
||||
options = websocket.recv()
|
||||
@@ -63,7 +90,7 @@ class TranscriptionServer:
|
||||
logging.warning("Client Queue Full. Asking client to wait ...")
|
||||
wait_time = self.get_wait_time()
|
||||
response = {
|
||||
"uid" : options["uid"],
|
||||
"uid": options["uid"],
|
||||
"status": "WAIT",
|
||||
"message": wait_time,
|
||||
}
|
||||
@@ -71,7 +98,7 @@ class TranscriptionServer:
|
||||
websocket.close()
|
||||
del websocket
|
||||
return
|
||||
|
||||
|
||||
client = ServeClient(
|
||||
websocket,
|
||||
multilingual=options["multilingual"],
|
||||
@@ -79,9 +106,9 @@ class TranscriptionServer:
|
||||
task=options["task"],
|
||||
client_uid=options["uid"]
|
||||
)
|
||||
|
||||
|
||||
self.clients[websocket] = client
|
||||
self.clients_start_time[websocket] = time.time()
|
||||
self.clients_start_time[websocket] = time.time()
|
||||
|
||||
while True:
|
||||
try:
|
||||
@@ -92,10 +119,11 @@ class TranscriptionServer:
|
||||
speech_prob = self.vad_model(torch.from_numpy(frame_np.copy()), self.RATE).item()
|
||||
if speech_prob < self.vad_threshold:
|
||||
continue
|
||||
|
||||
|
||||
except Exception as e:
|
||||
logging.error(e)
|
||||
return
|
||||
|
||||
self.clients[websocket].add_frames(frame_np)
|
||||
|
||||
elapsed_time = time.time() - self.clients_start_time[websocket]
|
||||
@@ -109,7 +137,6 @@ class TranscriptionServer:
|
||||
del websocket
|
||||
break
|
||||
|
||||
|
||||
except Exception as e:
|
||||
logging.error(e)
|
||||
self.clients[websocket].cleanup()
|
||||
@@ -117,7 +144,6 @@ class TranscriptionServer:
|
||||
self.clients_start_time.pop(websocket)
|
||||
logging.info("Connection Closed.")
|
||||
logging.info(self.clients)
|
||||
|
||||
del websocket
|
||||
break
|
||||
|
||||
@@ -134,11 +160,54 @@ class TranscriptionServer:
|
||||
|
||||
|
||||
class ServeClient:
|
||||
"""
|
||||
Attributes:
|
||||
RATE (int): The audio sampling rate (constant) set to 16000.
|
||||
SERVER_READY (str): A constant message indicating that the server is ready.
|
||||
DISCONNECT (str): A constant message indicating that the client should disconnect.
|
||||
client_uid (str): A unique identifier for the client.
|
||||
data (bytes): Accumulated audio data.
|
||||
frames (bytes): Accumulated audio frames.
|
||||
language (str): The language for transcription.
|
||||
task (str): The task type, e.g., "transcribe."
|
||||
transcriber (WhisperModel): The Whisper model for speech-to-text.
|
||||
timestamp_offset (float): The offset in audio timestamps.
|
||||
frames_np (numpy.ndarray): NumPy array to store audio frames.
|
||||
frames_offset (float): The offset in audio frames.
|
||||
text (list): List of transcribed text segments.
|
||||
current_out (str): The current incomplete transcription.
|
||||
prev_out (str): The previous incomplete transcription.
|
||||
t_start (float): Timestamp for the start of transcription.
|
||||
exit (bool): A flag to exit the transcription thread.
|
||||
same_output_threshold (int): Threshold for consecutive same output segments.
|
||||
show_prev_out_thresh (int): Threshold for showing previous output segments.
|
||||
add_pause_thresh (int): Threshold for adding a pause (blank) segment.
|
||||
transcript (list): List of transcribed segments.
|
||||
send_last_n_segments (int): Number of last segments to send to the client.
|
||||
wrapper (textwrap.TextWrapper): Text wrapper for formatting text.
|
||||
pick_previous_segments (int): Number of previous segments to include in the output.
|
||||
websocket: The WebSocket connection for the client.
|
||||
"""
|
||||
RATE = 16000
|
||||
SERVER_READY = "SERVER_READY"
|
||||
DISCONNECT = "DISCONNECT"
|
||||
|
||||
def __init__(self, websocket, task="transcribe", device=None, multilingual=False, language=None, client_uid=None):
|
||||
"""
|
||||
Initialize a ServeClient instance.
|
||||
The Whisper model is initialized based on the client's language and device availability.
|
||||
The transcription thread is started upon initialization. A "SERVER_READY" message is sent
|
||||
to the client to indicate that the server is ready.
|
||||
|
||||
Args:
|
||||
websocket (WebSocket): The WebSocket connection for the client.
|
||||
task (str, optional): The task type, e.g., "transcribe." Defaults to "transcribe".
|
||||
device (str, optional): The device type for Whisper, "cuda" or "cpu". Defaults to None.
|
||||
multilingual (bool, optional): Whether the client supports multilingual transcription. Defaults to False.
|
||||
language (str, optional): The language for transcription. Defaults to None.
|
||||
client_uid (str, optional): A unique identifier for the client. Defaults to None.
|
||||
|
||||
"""
|
||||
self.client_uid = client_uid
|
||||
self.data = b""
|
||||
self.frames = b""
|
||||
@@ -185,14 +254,21 @@ class ServeClient:
|
||||
|
||||
def fill_output(self, output):
|
||||
"""
|
||||
Format output with current and previous complete segments
|
||||
into two lines of 50 characters.
|
||||
Format the current incomplete transcription output by combining it with previous complete segments.
|
||||
The resulting transcription is wrapped into two lines, each containing a maximum of 50 characters.
|
||||
|
||||
It ensures that the combined transcription fits within two lines, with a maximum of 50 characters per line.
|
||||
Segments are concatenated in the order they exist in the list of previous segments, with the most
|
||||
recent complete segment first and older segments prepended as needed to maintain the character limit.
|
||||
If a 3-second pause is detected in the previous segments, any text preceding it is discarded to ensure
|
||||
the transcription starts with the most recent complete content. The resulting transcription is returned
|
||||
as a single string.
|
||||
|
||||
Args:
|
||||
output(str): current incomplete segment
|
||||
output(str): The current incomplete transcription segment.
|
||||
|
||||
Returns:
|
||||
transcription wrapped in two lines
|
||||
str: A formatted transcription wrapped in two lines.
|
||||
"""
|
||||
text = ''
|
||||
pick_prev = min(len(self.text), self.pick_previous_segments)
|
||||
@@ -206,6 +282,21 @@ class ServeClient:
|
||||
return wrapped
|
||||
|
||||
def add_frames(self, frame_np):
|
||||
"""
|
||||
Add audio frames to the ongoing audio stream buffer.
|
||||
|
||||
This method is responsible for maintaining the audio stream buffer, allowing the continuous addition
|
||||
of audio frames as they are received. It also ensures that the buffer does not exceed a specified size
|
||||
to prevent excessive memory usage.
|
||||
|
||||
If the buffer size exceeds a threshold (45 seconds of audio data), it discards the oldest 30 seconds
|
||||
of audio data to maintain a reasonable buffer size. If the buffer is empty, it initializes it with the provided
|
||||
audio frame. The audio stream buffer is used for real-time processing of audio data for transcription.
|
||||
|
||||
Args:
|
||||
frame_np (numpy.ndarray): The audio frame data as a NumPy array.
|
||||
|
||||
"""
|
||||
if self.frames_np is not None and self.frames_np.shape[0] > 45*self.RATE:
|
||||
self.frames_offset += 30.0
|
||||
self.frames_np = self.frames_np[int(30*self.RATE):]
|
||||
@@ -216,7 +307,20 @@ class ServeClient:
|
||||
|
||||
def speech_to_text(self):
|
||||
"""
|
||||
Process audio stream in an infinite loop.
|
||||
Process an audio stream in an infinite loop, continuously transcribing the speech.
|
||||
|
||||
This method continuously receives audio frames, performs real-time transcription, and sends
|
||||
transcribed segments to the client via a WebSocket connection.
|
||||
|
||||
If the client's language is not detected, it waits for 30 seconds of audio input to make a language prediction.
|
||||
It utilizes the Whisper ASR model to transcribe the audio, continuously processing and streaming results. Segments
|
||||
are sent to the client in real-time, and a history of segments is maintained to provide context.Pauses in speech
|
||||
(no output from Whisper) are handled by showing the previous output for a set duration. A blank segment is added if
|
||||
there is no speech for a specified duration to indicate a pause.
|
||||
|
||||
Raises:
|
||||
Exception: If there is an issue with audio processing or WebSocket communication.
|
||||
|
||||
"""
|
||||
# detect language
|
||||
if self.language is None:
|
||||
@@ -324,12 +428,21 @@ class ServeClient:
|
||||
Processes the segments from whisper. Appends all the segments to the list
|
||||
except for the last segment assuming that it is incomplete.
|
||||
|
||||
Updates the ongoing transcript with transcribed segments, including their start and end times.
|
||||
Complete segments are appended to the transcript in chronological order. Incomplete segments
|
||||
(assumed to be the last one) are processed to identify repeated content. If the same incomplete
|
||||
segment is seen multiple times, it updates the offset and appends the segment to the transcript.
|
||||
A threshold is used to detect repeated content and ensure it is only included once in the transcript.
|
||||
The timestamp offset is updated based on the duration of processed segments. The method returns the
|
||||
last processed segment, allowing it to be sent to the client for real-time updates.
|
||||
|
||||
Args:
|
||||
segments(dict) : dictionary of segments as returned by whisper
|
||||
duration(float): duration of the current chunk
|
||||
|
||||
Returns:
|
||||
transcription for the current chunk
|
||||
dict or None: The last processed segment with its start time, end time, and transcribed text.
|
||||
Returns None if there are no valid segments to process.
|
||||
"""
|
||||
offset = None
|
||||
self.current_out = ''
|
||||
@@ -388,6 +501,13 @@ class ServeClient:
|
||||
return last_segment
|
||||
|
||||
def disconnect(self):
|
||||
"""
|
||||
Notify the client of disconnection and send a disconnect message.
|
||||
|
||||
This method sends a disconnect message to the client via the WebSocket connection to notify them
|
||||
that the transcription service is disconnecting gracefully.
|
||||
|
||||
"""
|
||||
self.websocket.send(
|
||||
json.dumps(
|
||||
{
|
||||
@@ -398,6 +518,14 @@ class ServeClient:
|
||||
)
|
||||
|
||||
def cleanup(self):
|
||||
"""
|
||||
Perform cleanup tasks before exiting the transcription service.
|
||||
|
||||
This method performs necessary cleanup tasks, including stopping the transcription thread, marking
|
||||
the exit flag to indicate the transcription thread should exit gracefully, and destroying resources
|
||||
associated with the transcription process.
|
||||
|
||||
"""
|
||||
logging.info("Cleaning up.")
|
||||
self.exit = True
|
||||
self.transcriber.destroy()
|
||||
|
||||
Reference in New Issue
Block a user