| 1 | # SPDX-License-Identifier: Apache-2.0 |
| 2 | # SPDX-FileCopyrightText: Copyright contributors to the vLLM project |
| 3 | from __future__ import annotations |
| 4 | |
| 5 | from dataclasses import dataclass |
| 6 | from typing import TYPE_CHECKING |
| 7 | |
| 8 | from vllm.config.utils import config |
| 9 | |
| 10 | if TYPE_CHECKING: |
| 11 | import numpy as np |
| 12 | |
| 13 | from vllm.config.model import ModelConfig |
| 14 | |
| 15 | |
| 16 | @dataclass |
| 17 | class SpeechToTextParams: |
| 18 | """All parameters consumed by ``get_generation_prompt()``. |
| 19 | |
| 20 | ``TranscriptionRequest.build_stt_params()`` constructs this object, |
| 21 | mapping API-level fields into typed attributes. Models only receive |
| 22 | this object, so new parameters can be added here without changing the |
| 23 | ``get_generation_prompt`` signature. |
| 24 | """ |
| 25 | |
| 26 | audio: np.ndarray |
| 27 | """Resampled audio waveform for a single chunk.""" |
| 28 | |
| 29 | stt_config: SpeechToTextConfig |
| 30 | """Server-level speech-to-text configuration.""" |
| 31 | |
| 32 | model_config: ModelConfig |
| 33 | """Model configuration.""" |
| 34 | |
| 35 | language: str | None = None |
| 36 | """ISO 639-1 language code (validated / auto-detected).""" |
| 37 | |
| 38 | hotwords: str | None = None |
| 39 | """ |
| 40 | hotwords refers to a list of important words or phrases that the model |
| 41 | should pay extra attention to during transcription. |
| 42 | """ |
| 43 | |
| 44 | task_type: str = "transcribe" |
| 45 | """``"transcribe"`` or ``"translate"``.""" |
| 46 | |
| 47 | request_prompt: str = "" |
| 48 | """Optional text prompt to guide the model.""" |
| 49 | |
| 50 | to_language: str | None = None |
| 51 | """Target language for translation (model-dependent).""" |
| 52 | |
| 53 | |
| 54 | @config |
| 55 | class SpeechToTextConfig: |
| 56 | """Configuration for speech-to-text models.""" |
| 57 | |
| 58 | sample_rate: float = 16_000 |
| 59 | """Sample rate (Hz) to resample input audio to. Most speech models expect |
| 60 | 16kHz audio input. The input audio will be automatically resampled to this |
| 61 | rate before processing.""" |
| 62 | |
| 63 | max_audio_clip_s: int | None = 30 |
| 64 | """Maximum duration in seconds for a single audio clip without chunking. |
| 65 | Audio longer than this will be split into smaller chunks if |
| 66 | `allow_audio_chunking` evaluates to True, otherwise it will be rejected. |
| 67 | `None` means audio duration can be unlimited and won't be chunked.""" |
| 68 | |
| 69 | overlap_chunk_second: int = 1 |
| 70 | """Overlap duration in seconds between consecutive audio chunks when |
| 71 | splitting long audio. This helps maintain context across chunk boundaries |
| 72 | and improves transcription quality at split points.""" |
| 73 | |
| 74 | min_energy_split_window_size: int | None = 1600 |
| 75 | """Window size in samples for finding low-energy (quiet) regions to split |
| 76 | audio chunks. The algorithm looks for the quietest moment within this |
| 77 | window to minimize cutting through speech. Default 1600 samples ≈ 100ms |
| 78 | at 16kHz. If None, no chunking will be done.""" |
| 79 | |
| 80 | @property |
| 81 | def allow_audio_chunking(self) -> bool: |
| 82 | return ( |
| 83 | self.min_energy_split_window_size is not None |
| 84 | and self.max_audio_clip_s is not None |
| 85 | ) |