Repository: livekit/agents
File: livekit-plugins/livekit-plugins-soniox/livekit/plugins/soniox/stt.py (Python)

Code before:
                                f"WebSocket error: {content.get('error_code')}"
                                f" - {content.get('error_message')}"
                            )

                        if content.get("finished"):
                            logger.debug("Transcription finished")

                    except Exception as e:
                        logger.exception(f"Error processing message: {e}")

            except aiohttp.ClientError as e:
                logger.error(f"WebSocket error while receiving: {e}")
            except Exception as e:
                logger.error(f"Unexpected error while receiving messages: {e}")


class _TokenAccumulator:
    """Accumulates token metadata (text, language, speaker, timing, confidence).

    Tokens are assumed to arrive in chronological order, so start_time is taken
    from the first token and end_time is continuously overwritten by the latest.
    """

    def __init__(self) -> None:
        self.text: str = ""
        self.language: str = ""
        self.speaker_id: str | None = None
        self.start_time: float = 0.0
        self.end_time: float = 0.0
        self._confidence_sum: float = 0.0
        self._confidence_count: int = 0
        self._has_start_time: bool = False

    def update(self, token: dict[str, Any]) -> None:
        self.text += token["text"]
        if token.get("language") and not self.language:
            self.language = token["language"]
        if "speaker" in token and self.speaker_id is None:
            self.speaker_id = str(token["speaker"])
        if "start_ms" in token and not self._has_start_time:
            self._has_start_time = True
            self.start_time = float(token["start_ms"])
        if "end_ms" in token:
            self.end_time = float(token["end_ms"])
        if "confidence" in token:
            self._confidence_sum += token["confidence"]
            self._confidence_count += 1

    @property
    def confidence(self) -> float:
        if self._confidence_count == 0:

Review comment (refactor):
SpeechStream added a new field `_start_time_offset` to make sure the timestamps are aligned with our recordings, so we need to pass it here in construction and add them in SpeechData.

Nice abstraction BTW. Maybe we should add this to the core lib.

Code after:
                        if content.get("error_code") or content.get("error_message"):
                            logger.error(
                                f"WebSocket error: {content.get('error_code')}"
                                f" - {content.get('error_message')}"
                            )

                        if content.get("finished"):
                            logger.debug("Transcription finished")

                    except Exception as e:
                        logger.exception(f"Error processing message: {e}")

            except aiohttp.ClientError as e:
                logger.error(f"WebSocket error while receiving: {e}")
            except Exception as e:
                logger.error(f"Unexpected error while receiving messages: {e}")


class _TokenAccumulator:
    """Accumulates token metadata (text, language, speaker, timing, confidence).

    Tokens are assumed to arrive in chronological order, so start_time is taken
    from the first token and end_time is continuously overwritten by the latest.
    """

    def __init__(self) -> None:
        self.text: str = ""
        self.language: str = ""
        self.speaker_id: str | None = None
        self.start_time: float = 0.0
        self.end_time: float = 0.0
        self._confidence_sum: float = 0.0
        self._confidence_count: int = 0
        self._has_start_time: bool = False

    def update(self, token: dict[str, Any]) -> None:
        self.text += token["text"]
        if token.get("language") and not self.language:
            self.language = token["language"]
        if "speaker" in token and self.speaker_id is None:
            self.speaker_id = str(token["speaker"])
        if "start_ms" in token and not self._has_start_time:
            self._has_start_time = True
            self.start_time = float(token["start_ms"])
        if "end_ms" in token:
            self.end_time = float(token["end_ms"])
        if "confidence" in token:
            self._confidence_sum += token["confidence"]
            self._confidence_count += 1

    @property