From a38e62dcdd4e84b02ab004a167c30d1a666e0e17 Mon Sep 17 00:00:00 2001 From: Markus Hennerbichler Date: Wed, 31 Jan 2024 12:07:39 +0000 Subject: [PATCH] Add support for Audio Events --- speechmatics/cli.py | 15 +++++++++++++++ speechmatics/cli_parser.py | 6 ++++++ speechmatics/client.py | 16 ++++++++++------ speechmatics/models.py | 17 ++++++++++++++++- 4 files changed, 47 insertions(+), 7 deletions(-) diff --git a/speechmatics/cli.py b/speechmatics/cli.py index 03df295..3af76a3 100755 --- a/speechmatics/cli.py +++ b/speechmatics/cli.py @@ -26,6 +26,7 @@ from speechmatics.exceptions import JobNotFoundException, TranscriptionError from speechmatics.helpers import _process_status_errors from speechmatics.models import ( + AudioEventsConfig, AudioSettings, AutoChaptersConfig, BatchLanguageIdentificationConfig, @@ -341,6 +342,10 @@ def get_transcription_config( if args_auto_chapters or auto_chapters_config is not None: config["auto_chapters_config"] = AutoChaptersConfig() + arg_audio_events = args.get("audio_events") + if arg_audio_events: + config["audio_events_config"] = AudioEventsConfig() + if args["mode"] == "rt": # pylint: disable=unexpected-keyword-arg return TranscriptionConfig(**config) @@ -448,6 +453,14 @@ def transcript_handler(message): sys.stdout.write(f"{escape_seq}{plaintext}\n") transcripts.text += plaintext + def audio_event_handler(message): + if print_json: + print(json.dumps(message)) + return + event_name = message["event"].get("type", "").upper() + sys.stdout.write(f"{escape_seq}[{event_name}]\n") + transcripts.text += f"[{event_name}] " + def partial_translation_handler(message): if print_json: print(json.dumps(message)) @@ -480,6 +493,8 @@ def end_of_transcript_handler(_): # print both transcription and translation messages (if json was requested) # print translation (if text was requested then) # print transcription (if text was requested without translation) + + api.add_event_handler(ServerMessageType.AudioEventStarted, audio_event_handler) if print_json: if enable_partials or enable_translation_partials: api.add_event_handler( diff --git a/speechmatics/cli_parser.py b/speechmatics/cli_parser.py index 8170004..3d48b87 100644 --- a/speechmatics/cli_parser.py +++ b/speechmatics/cli_parser.py @@ -466,6 +466,12 @@ def get_arg_parser(): choices=["none", "speaker", "speaker_change"], help="Which type of diarization to use.", ) + + rt_transcribe_command_parser.add_argument( + "--audio-events", + action="store_true", + help="Print audio events to the console" + ) # Build our actual parsers. mode_subparsers = parser.add_subparsers(title="Mode", dest="mode") diff --git a/speechmatics/client.py b/speechmatics/client.py index c9869e5..68a8cad 100644 --- a/speechmatics/client.py +++ b/speechmatics/client.py @@ -72,7 +72,6 @@ def __init__( self.connection_settings.set_missing_values_from_config(UsageMode.RealTime) self.websocket = None self.transcription_config = None - self.translation_config = None self.event_handlers = {x: [] for x in ServerMessageType} self.middlewares = {x: [] for x in ClientMessageType} @@ -135,12 +134,15 @@ def _set_recognition_config(self): :py:attr:`speechmatics.models.ClientMessageType.SetRecognitionConfig` message. """ + assert self.transcription_config is not None msg = { "message": ClientMessageType.SetRecognitionConfig, "transcription_config": self.transcription_config.as_config(), } - if self.translation_config is not None: - msg["translation_config"] = self.translation_config.asdict() + if self.transcription_config.translation_config is not None: + msg["translation_config"] = self.transcription_config.translation_config.asdict() + if self.transcription_config.audio_events_config is not None: + msg["audio_events_config"] = self.transcription_config.audio_events_config.asdict() self._call_middleware(ClientMessageType.SetRecognitionConfig, msg, False) return msg @@ -155,13 +157,16 @@ def _start_recognition(self, audio_settings): :param audio_settings: Audio settings to use. :type audio_settings: speechmatics.models.AudioSettings """ + assert self.transcription_config is not None msg = { "message": ClientMessageType.StartRecognition, "audio_format": audio_settings.asdict(), "transcription_config": self.transcription_config.as_config(), } - if self.translation_config is not None: - msg["translation_config"] = self.translation_config.asdict() + if self.transcription_config.translation_config is not None: + msg["translation_config"] = self.transcription_config.translation_config.asdict() + if self.transcription_config.audio_events_config is not None: + msg["audio_events_config"] = self.transcription_config.audio_events_config.asdict() self.session_running = True self._call_middleware(ClientMessageType.StartRecognition, msg, False) LOGGER.debug(msg) @@ -435,7 +440,6 @@ async def run( consumer/producer tasks. """ self.transcription_config = transcription_config - self.translation_config = transcription_config.translation_config self.seq_no = 0 self._language_pack_info = None await self._init_synchronization_primitives() diff --git a/speechmatics/models.py b/speechmatics/models.py index 3461201..ba0ae91 100644 --- a/speechmatics/models.py +++ b/speechmatics/models.py @@ -211,6 +211,10 @@ class TopicDetectionConfig: class AutoChaptersConfig: """Auto Chapters config.""" +@dataclass +class AudioEventsConfig: + def asdict(self): + return asdict(self) @dataclass(init=False) class TranscriptionConfig(_TranscriptionConfig): @@ -254,12 +258,16 @@ class TranscriptionConfig(_TranscriptionConfig): """Indicates if partial translation, where words are produced immediately, is enabled.""" - translation_config: TranslationConfig = None + translation_config: Optional[TranslationConfig] = None """Optional configuration for translation.""" + + audio_events_config: Optional[AudioEventsConfig] = None + """Optional configuration for audio events""" def as_config(self): dictionary = self.asdict() dictionary.pop("translation_config", None) + dictionary.pop("audio_events_config", None) dictionary.pop("enable_translation_partials", None) enable_transcription_partials = dictionary.pop( "enable_transcription_partials", False @@ -504,6 +512,13 @@ class ServerMessageType(str, Enum): AddTranscript = "AddTranscript" """Indicates the final transcript of a part of the audio.""" + AudioEventStarted = "AudioEventStarted" + """Indicates the start of an audio event.""" + + AudioEventEnded = "AudioEventEnded" + """Indicates the end of an audio event.""" + + AddPartialTranslation = "AddPartialTranslation" """Indicates a partial translation, which is an incomplete translation that is immediately produced and may change as more context becomes available.