跳到內容

語音轉文字(轉錄/翻譯)支援

本文件將引導您完成為 vLLM 的轉錄和翻譯 API 新增語音轉文字(ASR)模型支援的步驟,方法是實現 SupportsTranscription。有關更多指導,請參閱 支援的模型

更新基礎 vLLM 模型

假設您已按照基本模型指南在 vLLM 中實現了模型。透過 SupportsTranscription 介面擴充套件您的模型,並實現以下類屬性和方法。

supported_languagessupports_transcription_only

宣告支援的語言和功能

  • supported_languages 對映在初始化時進行驗證。
  • 如果模型不應提供文字生成(例如 Whisper),請將 supports_transcription_only 設定為 True
supported_languages 和 supports_transcription_only
from typing import ClassVar, Mapping, Literal
import numpy as np
import torch
from torch import nn

from vllm.config import ModelConfig, SpeechToTextConfig
from vllm.inputs.data import PromptType
from vllm.model_executor.models.interfaces import SupportsTranscription

class YourASRModel(nn.Module, SupportsTranscription):
    # Map of ISO 639-1 language codes to language names
    supported_languages: ClassVar[Mapping[str, str]] = {
        "en": "English",
        "it": "Italian",
        # ... add more as needed
    }

    # If your model only supports audio-conditioned generation
    # (no text-only generation), enable this flag.
    supports_transcription_only: ClassVar[bool] = True

透過 get_speech_to_text_config 提供 ASR 配置。

這用於控制提供模型時的 API 的一般行為

get_speech_to_text_config()
class YourASRModel(nn.Module, SupportsTranscription):
    ...

    @classmethod
    def get_speech_to_text_config(
        cls,
        model_config: ModelConfig,
        task_type: Literal["transcribe", "translate"],
    ) -> SpeechToTextConfig:
        return SpeechToTextConfig(
            sample_rate=16_000,
            max_audio_clip_s=30,
            # Set to None to disable server-side chunking if your
            # model/processor handles it already
            min_energy_split_window_size=None,
        )

有關每個欄位的控制內容,請參閱 音訊預處理和分塊

透過 get_generation_prompt 實現提示構建。伺服器會向您傳遞重取樣後的波形和任務引數;您需要返回一個有效的 PromptType。有兩種常見模式:

帶音訊嵌入的多模態 LLM(例如,Voxtral、Gemma3n)

返回一個包含 multi_modal_data(帶音訊)以及 prompt 字串或 prompt_token_ids 的字典。

get_generation_prompt()
class YourASRModel(nn.Module, SupportsTranscription):
    ...

    @classmethod
    def get_generation_prompt(
        cls,
        audio: np.ndarray,
        stt_config: SpeechToTextConfig,
        model_config: ModelConfig,
        language: str | None,
        task_type: Literal["transcribe", "translate"],
        request_prompt: str,
        to_language: str | None,
    ) -> PromptType:
        # Example with a free-form instruction prompt
        task_word = "Transcribe" if task_type == "transcribe" else "Translate"
        prompt = (
            "<start_of_turn>user\n"
            f"{task_word} this audio: <audio_soft_token>"
            "<end_of_turn>\n<start_of_turn>model\n"
        )

        return {
            "multi_modal_data": {"audio": (audio, stt_config.sample_rate)},
            "prompt": prompt,
        }

有關多模態輸入的進一步說明,請參閱 多模態輸入

僅音訊的編碼器-解碼器(例如,Whisper)

返回一個包含單獨的 encoder_promptdecoder_prompt 條目的字典。

get_generation_prompt()
class YourASRModel(nn.Module, SupportsTranscription):
    ...

    @classmethod
    def get_generation_prompt(
        cls,
        audio: np.ndarray,
        stt_config: SpeechToTextConfig,
        model_config: ModelConfig,
        language: str | None,
        task_type: Literal["transcribe", "translate"],
        request_prompt: str,
        to_language: str | None,
    ) -> PromptType:
        if language is None:
            raise ValueError("Language must be specified")

        prompt = {
            "encoder_prompt": {
                "prompt": "",
                "multi_modal_data": {
                    "audio": (audio, stt_config.sample_rate),
                },
            },
            "decoder_prompt": (
                (f"<|prev|>{request_prompt}" if request_prompt else "")
                + f"<|startoftranscript|><|{language}|>"
                + f"<|{task_type}|><|notimestamps|>"
            ),
        }
        return cast(PromptType, prompt)

validate_language(可選)

透過 validate_language 進行語言驗證。

如果您的模型需要語言並且您想要一個預設值,請重寫此方法(參見 Whisper)。

validate_language()
@classmethod
def validate_language(cls, language: str | None) -> str | None:
    if language is None:
        logger.warning(
            "Defaulting to language='en'. If you wish to transcribe "
            "audio in a different language, pass the `language` field "
            "in the TranscriptionRequest."
        )
        language = "en"
    return super().validate_language(language)

get_num_audio_tokens(可選)

透過 get_num_audio_tokens 進行流式傳輸的令牌計數。

提供快速的持續時間到令牌的估計,以改進流式傳輸使用統計資訊。

get_num_audio_tokens()
class YourASRModel(nn.Module, SupportsTranscription):
    ...

    @classmethod
    def get_num_audio_tokens(
        cls,
        audio_duration_s: float,
        stt_config: SpeechToTextConfig,
        model_config: ModelConfig,
    ) -> int | None:
        # Return None if unknown; otherwise return an estimate.
        return int(audio_duration_s * stt_config.sample_rate // 320)  # example

音訊預處理和分塊

API 伺服器負責基本的音訊 I/O 和可選的分塊,然後再構建提示。

  • 重取樣:使用 librosa 將輸入音訊重取樣到 SpeechToTextConfig.sample_rate
  • 分塊:如果 SpeechToTextConfig.allow_audio_chunking 為 True 且持續時間超過 max_audio_clip_s,伺服器會將音訊分割成重疊的塊,併為每個塊生成一個提示。重疊由 overlap_chunk_second 控制。
  • 能量感知分割:當設定 min_energy_split_window_size 時,伺服器會尋找低能量區域,以儘量減少在單詞內部切割。

相關的伺服器邏輯

_preprocess_speech_to_text()
# vllm/entrypoints/openai/speech_to_text.py
async def _preprocess_speech_to_text(...):
    language = self.model_cls.validate_language(request.language)
    ...
    y, sr = librosa.load(bytes_, sr=self.asr_config.sample_rate)
    duration = librosa.get_duration(y=y, sr=sr)
    do_split_audio = (self.asr_config.allow_audio_chunking
                    and duration > self.asr_config.max_audio_clip_s)
    chunks = [y] if not do_split_audio else self._split_audio(y, int(sr))
    prompts = []
    for chunk in chunks:
        prompt = self.model_cls.get_generation_prompt(
            audio=chunk,
            stt_config=self.asr_config,
            model_config=self.model_config,
            language=language,
            task_type=self.task_type,
            request_prompt=request.prompt,
            to_language=to_language,
        )
        prompts.append(prompt)
    return prompts, duration

自動暴露任務

如果您的模型實現了該介面,vLLM 將自動宣告轉錄支援。

if supports_transcription(model):
    if model.supports_transcription_only:
        return ["transcription"]
    supported_tasks.append("transcription")

啟用後,伺服器將初始化轉錄和翻譯處理程式。

state.openai_serving_transcription = OpenAIServingTranscription(...) if "transcription" in supported_tasks else None
state.openai_serving_translation = OpenAIServingTranslation(...) if "transcription" in supported_tasks else None

除了透過模型登錄檔提供您的模型類並實現 SupportsTranscription 之外,無需額外的註冊。

內建示例

透過 API 進行測試

一旦您的模型實現了 SupportsTranscription,您就可以測試端點(API 模擬 OpenAI)。

  • 轉錄(ASR)

    curl -s -X POST \
      -H "Authorization: Bearer $VLLM_API_KEY" \
      -H "Content-Type: multipart/form-data" \
      -F "file=@/path/to/audio.wav" \
      -F "model=$MODEL_ID" \
      https://:8000/v1/audio/transcriptions
    
  • 翻譯(源 → 英語,除非另有支援)

    curl -s -X POST \
      -H "Authorization: Bearer $VLLM_API_KEY" \
      -H "Content-Type: multipart/form-data" \
      -F "file=@/path/to/audio.wav" \
      -F "model=$MODEL_ID" \
      https://:8000/v1/audio/translations
    

或者檢視 更多示例中的 online_serving

注意

  • 如果您的模型內部處理分塊(例如,透過其處理器或編碼器),請在返回的 SpeechToTextConfig 中將 min_energy_split_window_size 設定為 None 以停用伺服器端分塊。
  • 實現 get_num_audio_tokens 可以提高流式傳輸使用情況指標(prompt_tokens)的準確性,而無需額外的正向傳遞。
  • 對於多語言行為,請使 supported_languages 與實際模型功能保持一致。