跳至内容

Mistral 的 Voxtral:指南与演示项目

了解如何使用 vLLM 运行 Mistral 的 Voxtral Mini 3B 模型,设置 API,并构建一个基于 Streamlit 的音频摘要与问答应用。
已更新 2026年10月6日  · 12分钟 阅读

使用 AI 探索

ChatGPTClaudePerplexity

Mistral 近期发布了其首个开源多模态音频模型 Voxtral Small 与 Voxtral Mini,基于 Mistral 3B 架构构建,并专为音频理解与转写任务做了优化。

本文将重点介绍 Voxtral Mini 3B——一款紧凑的开源模型,面向实时语音转文本任务,如转写、摘要与问答。凭借高效的参数规模与长上下文推理支持,Voxtral Mini 在与 vLLM 等高吞吐推理框架搭配时尤为强大,非常适合构建快速、离线的音频应用。

在本教程中,我将带您完成以下内容:

  • 在 Colab Pro 上使用 vLLM 运行 Voxtral Mini 3B
  • 部署通过 ngrok 隧道暴露的 API 端点,从任意位置访问您的模型
  • 构建一个基于 Streamlit 的音频助手,使用原始音频输入完成转写、摘要与问答

我们通过每周五发布的免费新闻简报 The Median 为读者带来 AI 前沿动态,精炼解读本周要闻。订阅即可每周用几分钟保持敏锐:

什么是 Mistral 的 Voxtral?

Voxtral 是 Mistral 的全开源音频模型家族,面向强大的语音理解能力。Voxtral 提供两种模型规模:

  • Voxtral Small:240 亿参数,适用于生产级企业场景
  • Voxtral Mini:30 亿参数,优化用于在边缘设备本地运行

mistral's voxtral benchmarks

来源:Mistral

Voxtral 接受原始音频输入(如 .wav 或 .mp3),并经过训练以高效地从语音内容中生成转写与摘要。Voxtral 作为更小的变体,针对快速推理与离线部署进行了优化。

它遵循 Mistral 的模型格式,并兼容 vLLM 等高吞吐推理框架,因此非常适合实时转写或轻量级语音应用。

如何使用 vLLM 运行 Voxtral Mini 3B

本节将演示如何在启用了 T4 GPU 的 Colab Pro 上通过 vLLM 部署 Voxtral Mini 3B。选择 vLLM 是因为其高吞吐、低延迟的服务能力,非常适合像 Voxtral 这样需要音频支持与快速流式响应的模型。

此外,我们还将使用 PyNGrok 通过公共端点暴露 vLLM 服务器,使本地运行的应用也能访问它。

步骤 1:安装依赖

首先在 Colab 环境中安装依赖。在 Colab 单元中运行以下命令:

!uv pip install -U transformers accelerate "vllm[audio]" --torch-backend=auto --extra-index-url https://wheels.vllm.ai/nightly

我们使用uv(更快的 Python 包安装器)来安装所需库。该命令会拉取包含对 Voxtral 等音频-语言模型实验性支持的 vllm[audio] 夜ly版本。如果您的环境尚未安装 uv,请先运行以下代码安装:

!pip install uv

步骤 2:安装 Mistral-Common

接下来安装 mistral-common 包,它提供与 Voxtral 及其他 Mistral 系列模型交互所需的基础工具。该包包含与官方实现一致的分词器以及基于 Pydantic 的消息结构校验。

!pip install mistral-common --upgrade
!python -c "import mistral_common; print(mistral_common.__version__)"

mistral-common 包含适用于 Voxtral 和其他 Mistral 家族模型的实用模块,包括分词器、Pydantic 格式的类型化消息与音频辅助函数。此步骤可确保与 Voxtral 在音频输入与结构化消息的内部处理保持兼容。

步骤 3:设置 VLLM

完成基础的 Mistral 依赖后,接下来通过克隆主仓库来设置 vLLM。

步骤 3.1:克隆 vLLM 仓库

克隆官方 vLLM GitHub 仓库,以便使用内置音频示例,并作为启动离线或托管推理的基础。

!git clone https://github.com/vllm-project/vllm && cd vllm

步骤 3.2:运行示例音频推理 

先做一次快速自检,确认环境设置正确。

!python vllm/examples/offline_inference/audio_language.py --num-audios 2 --model-type voxtral

我运行了离线示例 audio_language.py,使用 Voxtral 模型对两个预置样本进行音频-语言推理,以确认音频解码与生成流程是否正常。

步骤 4:设置 PyGrok

在完成 vLLM 配置后,使用 PyNGrok 将 Colab 上的 vLLM 服务器通过一个可公开访问的地址暴露出去。

  • 首先在 https://ngrok.com/ 注册一个免费账号
  • 在 Connect 选项卡下向下滚动,复制认证令牌(下图已隐藏),并将其保存到 Colab Secrets 中。

NGrok Token

接着在 Colab 环境中安装 PyNGrok,并使用之前复制的 NGROK token 设置认证。如果您只是做原型,也可以直接在此处传入 token。

!pip install pyngrok -q
from pyngrok import ngrok
ngrok.set_auth_token("NGROK_TOKEN")

步骤 5:服务化模型

这是关键步骤:通过 vLLM 启动 Voxtral Mini 3B 模型。

!vllm serve mistralai/Voxtral-Mini-3B-2507 --tokenizer_mode mistral --config_format mistral --load_format mistral --max-model-len 4864

上述代码片段包含多个重要参数:

  • --tokenizer_mode mistral:使用针对 Mistral 的分词器以获得准确分词。
  • --config_format mistral 与 --load_format mistral:确保模型配置与权重按 Mistral 自定义格式加载,保持兼容性。
  • --max-model-len 4864:将最大输入上下文长度设置为 4864 个 token。

注意:请保持该单元运行,因为这是一个活动的模型服务。

步骤 6:获取 NGrok 公共端点

当 vLLM 服务器运行后,在 Python 终端逐行运行以下代码:

from pyngrok import ngrok
ngrok.set_auth_token(NGROK_TOKEN)
public_url = ngrok.connect(8000)
print("Public endpoint:", public_url)

上述代码会将模型暴露到互联网的临时公共 URL,例如:

https://80xxxxxxxxxx.ngrok-free.app

保存该 URL,稍后会在本地的 config.py 中用于连接远程模型。运行结束后可通过以下命令终止连接:

ngrok.kill()

构建音频转写与摘要演示

本节我们将构建一个 Streamlit 界面,用于:

  1. 接收音频作为输入(用户上传)
  2. 通过 vLLM 服务器将音频发送至模型
  3. 展示转写与摘要,并允许用户进行提问

步骤 1:设置依赖

在构建应用前,将所有依赖写入 requirements.txt 文件。这样可确保本地运行或 Colab 笔记本之间的环境一致性。

streamlit>=1.28.0
openai>=1.0.0
mistral-common>=0.0.12
huggingface-hub>=0.19.0
pyngrok>=6.0.0
requests>=2.28.0
pydub>=0.25.1 

各依赖的用途如下:

  • streamlit:用于构建交互式音频界面。
  • openai:使用 OpenAI SDK 与兼容 Voxtral 的 vLLM 服务器交互。
  • mistral-common:提供 Voxtral 专用工具,如 AudioChunk 与 TextChunk。
  • pyngrok:将本地 vLLM 服务器暴露到互联网,便于 Streamlit 应用访问。
  • Pydub:用于将音频文件转换为可推理的格式。
  • huggingface-hub 与 requests:用于拉取模型与配置(如有需要)。

步骤 2:设置环境变量

为保持配置清晰与可移植,我们将 API 细节保存为环境变量。可在 .env 文件中定义:

VOXTRAL_API_KEY=dummy-key
VOXTRAL_API_BASE=NGROK_TOKEN/v1
VOXTRAL_MODEL_NAME=mistralai/Voxtral-Mini-3B-2507

VOXTRAL_API_BASE 应指向正在运行的 vLLM 实例,可以是本地(http://localhost:8000)或类似 https://80xxxxxxxxxx.ngrok-free.app 的 ngrok 公共端点。

注意:为兼容 OpenAI,请确保在 API base 末尾追加 /v1。

步骤 3:设置配置文件

为使应用模块化、易于调整并具备生产可用性,我们将在 config.py 中定义中心化的配置类。该文件将控制模型设置、API 访问、支持的音频格式、语言与 UI 偏好。

步骤 3.1:加载环境变量

在定义配置类之前,先加载保存在 .env 文件中的环境变量。这样可将敏感信息与代码分离。

import os
from typing import Optional
from pathlib import Path
# Load environment variables from .env file
env_file = Path(".env")
if env_file.exists():
    with open(env_file, 'r') as f:
        for line in f:
            if line.strip() and not line.startswith('#'):
                key, value = line.strip().split('=', 1)
                os.environ[key] = value

该代码会检查根目录下是否存在 .env 文件;若存在,则读取键值对并设置为环境变量。之后即可通过 os.getenv() 访问这些值,避免将密钥硬编码进应用。

步骤 3.2:定义 Config 类

现在将所有设置封装进整洁的 Config 类,便于访问与复用。

class Config:
    # API Configuration
    VOXTRAL_API_KEY: str = os.getenv("VOXTRAL_API_KEY", "EMPTY")
    VOXTRAL_API_BASE: str = os.getenv("VOXTRAL_API_BASE", "http://localhost:8000/v1")
    # Model Configuration
    MODEL_NAME: str = os.getenv("VOXTRAL_MODEL_NAME", "voxtral-mini-3b-2507")
    # Default Parameters
    DEFAULT_TEMPERATURE: float = 0.2
    DEFAULT_TOP_P: float = 0.95
    # Audio Configuration
    MAX_AUDIO_SIZE_MB: int = 100
    SUPPORTED_AUDIO_FORMATS: list = ['mp3', 'wav', 'm4a', 'flac', 'ogg']
    SUPPORTED_LANGUAGES: list = [
        "English", "Spanish", "French", "German", "Italian", "Portuguese", 
        "Russian", "Chinese", "Japanese", "Korean", "Arabic", "Hindi"
    ]
    # UI Configuration
    STREAMLIT_THEME: dict = {
        "primaryColor": "#1f77b4",
        "backgroundColor": "#ffffff",
        "secondaryBackgroundColor": "#f0f2f6",
        "textColor": "#262730",
        "font": "sans serif"
    }
    @classmethod
    def get_api_config(cls) -> dict:
        return {
            "api_key": cls.VOXTRAL_API_KEY,
            "base_url": cls.VOXTRAL_API_BASE,
            "model_name": cls.MODEL_NAME
        }    
    @classmethod
    def validate_config(cls) -> bool:
        if not cls.VOXTRAL_API_BASE:
            return False
        return True    
    @classmethod
    def get_language_code(cls, language_name: str) -> Optional[str]:
        language_mapping = {
            "English": "en",
            "Spanish": "es", 
            "French": "fr",
            "German": "de",
            "Italian": "it",
            "Portuguese": "pt",
            "Russian": "ru",
            "Chinese": "zh",
            "Japanese": "ja",
            "Korean": "ko",
            "Arabic": "ar",
            "Hindi": "hi"
        }
        return language_mapping.get(language_name) 

上述 Config 类充当基于 Voxtral 的应用的集中式控制台。无论是配置模型参数、管理音频格式,还是设定应用主题,该结构都能确保良好的抽象、代码复用与可维护性。

该类包含:

  • get_api_config() 方法:集中管理所有与 API 相关的凭据。应用中任何调用 Voxtral 模型的地方,只需调用 Config.get_api_config() 即可一次性获取所需参数。
  • validate_config() 方法:在开始推理之前,用于校验关键配置值(如 base URL)是否正确定义,从而及早发现问题并提示用户。
  • get_language_code() 方法:通过将 UI 中的语言名称(如 “French”)映射为标准 ISO 语言代码(如 “fr”),实现多语言问答;若传入不支持的语言,将安全返回 None。

步骤 4:构建 Streamlit 应用

下面逐步搭建应用界面与逻辑。

步骤 4.1:设置布局与样式

本步骤初始化Streamlit 前端,加载依赖并设置 CSS 样式,构建应用的视觉与功能基础。

import streamlit as st
import tempfile
import os
from mistral_common.protocol.instruct.messages import TextChunk, AudioChunk, UserMessage
from mistral_common.audio import Audio
from openai import OpenAI
import time
from config import Config
# Page configuration
st.set_page_config(
    page_title="Voxtral Audio Assistant",
    page_icon="🎵",
    layout="wide",
    initial_sidebar_state="expanded"
)
# Custom CSS 
st.markdown("""
<style>
    .main-header {
        
        font-weight: bold;
        
        text-align: center;
        
    }
    .section-header {
        
        font-weight: bold;
        
        
    }
    .info-box {
        background-
        
        border-radius: 0.5rem;
        border-left: 4px solid #1f77b4;
        
    }
    .success-box {
        background-
        
        border-radius: 0.5rem;
        border-left: 4px solid #28a745;
        
    }
    .chat-message {
        
        border-radius: 0.5rem;
        
    }
    .user-message {
        background-
        border-left: 4px solid #2196f3;
    }
    .assistant-message {
        background-
        border-left: 4px solid #9c27b0;
    }
</style>
""", unsafe_allow_html=True)

上述 Python 与 CSS 代码中:

  • 导入了用于 UI、文件处理以及通过 Voxtral 的 mistral_common 包进行音频/文本消息格式化的关键库。
  • 配置了 Streamlit 应用布局,为默认展开的侧边栏与双栏界面。
  • 注入自定义 CSS,将标题、音频区块、聊天气泡与摘要等区域做了视觉分隔,通过样式化标题、信息提示与区分用户与助手的气泡来强化层次结构。

步骤 4.2:初始化会话与客户端

接下来通过初始化会话变量与客户端,确保应用在刷新时行为一致。

def init_session_state():
    defaults = {
        'transcription': "",
        'summary': "",
        'chat_history': [],
        'audio_file_path': None
    }
    for key, default_value in defaults.items():
        if key not in st.session_state:
            st.session_state[key] = default_value
def initialize_client():
    config = Config.get_api_config() 
    client = OpenAI(
        api_key=config["api_key"],
        base_url=config["base_url"],
    ) 
    # Test connection
    try:
        models = client.models.list()
        return client
    except Exception as e:
        st.error(f"Failed to connect to Voxtral API: {str(e)}")
        st.info("Make sure your ngrok tunnel is running in Google Colab")
        return None

该代码用于设置应用内部状态并连接 Voxtral API 服务器,包含两部分:

  1. 会话初始化:确保诸如转写、摘要与上传的音频文件等数据在交互与刷新间保持正确存在。
  2. 客户端初始化:通过 vLLM 暴露的 OpenAI 兼容端点连接本地托管的 Voxtral Mini 3B 模型(经 Ngrok 转发)。若连接失败,会在 UI 中显示错误。

步骤 4.3:音频分块与实时转写

此步骤负责准备音频文件并调用 Voxtral Mini 3B 生成转写。

def file_to_chunk(file_path: str) -> AudioChunk:
    audio = Audio.from_file(file_path, strict=False)
    return AudioChunk.from_audio(audio)
def transcribe_audio(client, audio_file_path):
    try:
        with open(audio_file_path, "rb") as f:
            response = client.audio.transcriptions.create(
                file=f,
                model=Config.MODEL_NAME,
                response_format="text",
                stream=True
            )       
            transcription = ""
            progress_bar = st.progress(0)
            status_text = st.empty()
            # Collect all chunks first to get total count
            chunks = list(response)
            total_chunks = len(chunks)
            for i, chunk in enumerate(chunks):
                delta = chunk.choices[0].get("delta", {}).get("content")
                if delta:
                    transcription += delta
                    progress = min((i + 1) / max(total_chunks, 1), 1.0)
                    progress_bar.progress(progress)
                    status_text.text(f"Transcribing... {len(transcription)} characters")
            progress_bar.empty()
            status_text.empty()
            return transcription
    except Exception as e:
        st.error(f"Error during transcription: {str(e)}")
        return None

这里包含两个关键函数:

  1. 音频分块转换:先将上传的音频文件转换为 AudioChunk 格式,这是 Voxtral API 的输入要求。
  2. 带进度反馈的流式转写:以流式方式(stream=True)将音频发送至模型并逐块解码。随着 token 返回,进度条动态更新,为用户提供实时转写进度反馈。

步骤 4.4:生成音频摘要

此步骤将音频输入与文本提示一同发送给 Voxtral 模型,返回精炼且结构化的音频内容摘要。

def generate_summary(client, audio_file_path):
    try:
        audio_chunk = file_to_chunk(audio_file_path)
        text_chunk = TextChunk(text="Please provide a comprehensive summary of this audio content, highlighting the key points and main themes discussed.")
        user_msg = UserMessage(content=[audio_chunk, text_chunk]).to_openai()    
        response = client.chat.completions.create(
            model=Config.MODEL_NAME,
            messages=[user_msg],
            temperature=Config.DEFAULT_TEMPERATURE,
            top_p=Config.DEFAULT_TOP_P,
        )
        return response.choices[0].message.content
    except Exception as e:
        st.error(f"Error generating summary: {str(e)}")
        return None

上述代码通过以下关键方法与函数,从上传的音频生成摘要:

  • audio_chunk:先将上传的音频文件转换为 AudioChunk,用于 Voxtral 的音频处理。
  • text_chunk:使用文本提示要求模型清晰且全面地进行内容概括。
  • UserMessage:将 audio_chunk 与 text_chunk 组合为单个 OpenAI 兼容的多模态消息。
  • Response.choices[0].message.content:从模型响应中提取实际摘要文本。

步骤 4.5:多语言音频问答

现在我们已有摘要,接下来允许用户就上传的音频内容提出自然语言问题。该功能利用 Voxtral 的多模态能力,将音频与文本提示结合,生成具备上下文意识的答案。

下面的函数也支持多语言回答,会根据所选语言动态修改提示。

def ask_question(client, audio_file_path, question, language="English"):
    try:
        audio_chunk = file_to_chunk(audio_file_path)
        if language != "English":
            question = f"Please answer the following question in {language}: {question}"
        text_chunk = TextChunk(text=question)
        user_msg = UserMessage(content=[audio_chunk, text_chunk]).to_openai()        
        response = client.chat.completions.create(
            model=Config.MODEL_NAME,
            messages=[user_msg],
            temperature=Config.DEFAULT_TEMPERATURE,
            top_p=Config.DEFAULT_TOP_P,
        )        
        return response.choices[0].message.content
    except Exception as e:
        st.error(f"Error asking question: {str(e)}")
        return None

上述代码的执行流程如下:

  • ask_question() 函数允许用户就上传的音频提出任意问题。
  • 首先使用可复用的 file_to_chunk() 函数将上传文件转换为 AudioChunk,以满足 Voxtral 多模态 API 的输入格式。
  • 随后检查所选语言;若非英语,则在用户问题前添加指令,要求模型使用指定语言作答(如印地语或西班牙语)。
  • 将用户问题包装为 TextChunk,并与音频一并封装为多模态 UserMessage。
  • 将该消息发送至模型,并使用配置中的 temperature 与 top-p 值控制生成质量。
  • 模型返回单轮回答。

步骤 4.6:设置侧边栏

侧边栏相当于控制面板,允许用户管理会话设置、选择输出语言、测试与 Voxtral API 的连接,并通过滑块直观地自定义模型的回答行为。

def render_sidebar():
    with st.sidebar:
        st.markdown('<h3 class="section-header">Configuration</h3>', unsafe_allow_html=True)        
        # Connection status
        st.markdown('<h4>Connection Status</h4>', unsafe_allow_html=True)
        if st.button("Test Connection"):
            client = initialize_client()
            if client:
                st.success("Connected to Voxtral API")
            else:
                st.error("Connection failed")        
        # Language selection
        selected_language = st.selectbox("Select language for Q&A:", Config.SUPPORTED_LANGUAGES)        
        # Model configuration
        st.markdown('<h4>Model Settings</h4>', unsafe_allow_html=True)
        temperature = st.slider("Temperature", 0.0, 1.0, Config.DEFAULT_TEMPERATURE, 0.1)
        top_p = st.slider("Top P", 0.0, 1.0, Config.DEFAULT_TOP_P, 0.05)
        if st.button("Clear Session"):
            for key in ['transcription', 'summary', 'chat_history', 'audio_file_path']:
                st.session_state[key] = "" if key in ['transcription', 'summary'] else [] if key == 'chat_history' else None
            st.rerun()        
        return selected_language, temperature, top_p

上述代码要点:

  • 侧边栏:通过 st.sidebar 打开可收起的侧边栏,放置应用配置工具。
  • 连接测试:“Test Connection” 按钮会触发 initialize_client() 函数,尝试连接 Voxtral API,并通过 Streamlit 提示显示成功或失败。
  • 语言选择:下拉菜单让用户从 12 种支持语言中进行选择,此选择将用于指示模型以该语言作答。
  • 模型参数:滑块用于控制以下参数:
    • temperature:控制“创造性”。值越低越确定性,值越高越多样化。
    • top_p:控制核采样,将生成限制在最可能的 token 上。
  • 会话重置:“Clear Session” 按钮会重置所有会话状态变量,并重新运行应用。

步骤 4.7:音频上传与处理区

该部分允许用户上传音频文件(如 .mp3、.wav 等),文件会被临时保存。上传后,用户可选择进行转写或生成高层摘要。

def render_audio_processing():
    st.markdown('<h3 class="section-header">Audio Upload & Processing</h3>', unsafe_allow_html=True)    
    uploaded_file = st.file_uploader(
        "Choose an audio file",
        type=Config.SUPPORTED_AUDIO_FORMATS,
        help="Upload an audio file to transcribe and analyze"
    )
    if uploaded_file is not None:
        with tempfile.NamedTemporaryFile(delete=False, suffix=f".{uploaded_file.name.split('.')[-1]}") as tmp_file:
            tmp_file.write(uploaded_file.getvalue())
            st.session_state.audio_file_path = tmp_file.name
        st.success(f"File uploaded: {uploaded_file.name}")
        # Initialize client
        client = initialize_client()
        col1, col2 = st.columns(2) 
        with col1:
            if st.button("Generate Summary", type="primary"):
                with st.spinner("Generating summary..."):
                    summary = generate_summary(client, st.session_state.audio_file_path)
                    if summary:
                        st.session_state.summary = summary
        with col2:
            if st.button("Transcribe Audio", type="secondary"):
                with st.spinner("Transcribing audio..."):
                    transcription = transcribe_audio(client, st.session_state.audio_file_path)
                    if transcription:
                        st.session_state.transcription = transcription
        if st.session_state.summary:
            st.markdown('<h4>Summary</h4>', unsafe_allow_html=True)
            st.markdown(f'<div class="success-box">{st.session_state.summary}</div>', unsafe_allow_html=True)
        if st.session_state.transcription:
            st.markdown('<h4>Audio Transcription</h4>', unsafe_allow_html=True)
            st.text_area("Transcription", st.session_state.transcription, height=200, label_visibility="collapsed")

我们采用模块化结构,便于音频上传、处理与结果在多次交互间持久化。具体如下:

  • 文件上传器:提供拖放式文件上传,支持 Config.SUPPORTED_AUDIO_FORMATS 中的多种格式。上传后写入临时文件,并保存路径至 st.session_state.audio_file_path。
  • 客户端初始化:初始化兼容 Voxtral 的客户端,以便调用摘要与转写。
  • 摘要与转写按钮:定义两个按钮:
    • 生成摘要:点击后携带摘要提示将音频发送给模型。显示进度指示,成功则将输出保存至 st.session_state.summary。
    • 转写音频:将音频文件发送至转写端点。通过指示器展示实时进度,结果存入 st.session_state.transcription。
  • 最后在文本区域展示两个结果。

步骤 4.8:交互式多语言问答

此步骤允许用户使用多种语言(如英语、印地语、西班牙语)就上传的音频提出问题。所选语言将用于格式化模型的回复。每个问答对会存储在由会话管理的对话历史中,并以聊天气泡形式展示。

def render_qa_section(selected_language):
    st.markdown('<h3 class="section-header">Multilingual Q&A</h3>', unsafe_allow_html=True) 
    if st.session_state.audio_file_path:
        st.markdown(f'<div class="info-box">Selected language: <strong>{selected_language}</strong></div>', unsafe_allow_html=True)
        question = st.text_input(
            f"Ask a question about the audio (in {selected_language}):",
            placeholder="e.g., What is the main topic discussed?"
        )    
        if st.button("Ask Question", type="primary") and question:
            client = initialize_client()
            with st.spinner("Processing your question..."):
                answer = ask_question(client, st.session_state.audio_file_path, question, selected_language)
                if answer:
                    # Chat history
                    st.session_state.chat_history.append({
                        "question": question,
                        "answer": answer,
                        "language": selected_language,
                        "timestamp": time.strftime("%H:%M:%S")
                    })
                    st.success("Question answered!")
                else:
                    st.error("Failed to get answer. Please try again.")
                if st.session_state.chat_history:
            st.markdown('<h4>Conversation History</h4>', unsafe_allow_html=True)
            for chat in reversed(st.session_state.chat_history):
                st.markdown(f'<div class="chat-message user-message"><strong>Question:</strong> {chat["question"]}</div>', unsafe_allow_html=True)
                st.markdown(f'<div class="chat-message assistant-message"><strong>Answer:</strong> {chat["answer"]}</div>', unsafe_allow_html=True)
                st.markdown("---")
    else:
        st.markdown('<div class="info-box">Please upload an audio file to start asking questions.</div>', unsafe_allow_html=True)

上述代码的要点如下:

  • Ask Question 按钮:文本输入框允许用户以所选语言输入问题并点击 Ask Question 按钮。点击后会:
    • 初始化兼容 Voxtral 的客户端。
    • 将问题与上传的音频一并发送给模型。
    • 在等待模型响应时显示进度指示。
  • 响应处理:若收到响应,将:
    • 连同时间戳一并存入 st.session_state.chat_history。
    • 使用前文的自定义 CSS(用户与助手分别样式)进行渲染。
    • 若模型失败,将显示清晰的错误信息。
  • 对话历史:若存在历史问答,将按时间逆序展示并以分隔线区分。

步骤 4.9:启动应用

最后一步将前面定义的组件整合在一起,包括初始化会话状态、渲染侧边栏、处理音频上传、转写、摘要与问答,并采用双栏布局。

当服务器运行且依赖安装完成后,该步骤将通过 Streamlit 在浏览器中提供应用,准备好进行交互。

def main():
    st.markdown('<h1 class="main-header">🎵 Voxtral Audio Assistant</h1>', unsafe_allow_html=True)
    # Initialize session state
    init_session_state()
    # Render sidebar and get configuration
    selected_language, temperature, top_p = render_sidebar()
    col1, col2 = st.columns([1, 1]) 
    with col1:
        render_audio_processing()
    with col2:
        render_qa_section(selected_language)
    st.markdown("---")
    st.markdown("""
    <div style="text-align: center;">
        <p>Powered by <strong>Voxtral Mini 3B</strong> | Built with Streamlit</p>
        <p>Supports multiple languages for audio analysis and Q&A</p>
    </div>
    """, unsafe_allow_html=True)
if __name__ == "__main__":
    main() 

main() 函数是应用入口,负责布局控制、渲染编排,并确保所有会话变量与 UI 组件正确初始化。上述各函数的职责如下:

  • init_session_state():准备 transcription、summary 与 chat_history 等默认值,以在交互间持久保存应用状态。
  • render_sidebar():加载配置控件,包括语言选择、连接测试与模型参数。
  • render_audio_processing():支持用户上传并处理音频以进行转写与摘要生成。
  • render_qa_section():实现对上传音频的多语言问答。

准备就绪后,运行应用:

pip install -r requirements.txt

请确保它可通过 config.py 中 VOXTRAL_API_BASE 指定的 URL 访问。安装完所有依赖后,在终端运行以下命令启动 Streamlit 应用:

streamlit run app.py

浏览器将自动打开界面。此时应用已具备音频上传、实时转写、摘要与多语言问答等完整功能,由 Voxtral Mini 3B 提供支持。

您可以在我创建的这个GitHub 仓库中找到文中涉及的全部代码。

结语

Voxtral Mini 3B 是一款高效的开源权重模型,面向语音转写与理解。在本教程中,我们使用 vLLM 运行了它,设置了 API,并基于 Streamlit 构建了音频摘要应用。

无论您是在构建播客摘要、会议助手,还是语音指令应用,Voxtral Mini 都能为快速、本地的音频推理提供坚实基础。


Aashi Dutt's photo
Author
Aashi Dutt
LinkedIn
Twitter

我是一名 Google Developers 机器学习(生成式 AI)领域的专家、Kaggle 三项专家,以及 Women Techmakers 大使,拥有 3 年以上的技术从业经验。2020 年我共同创办了一家健康科技初创公司,目前在佐治亚理工学院攻读计算机科学硕士,专攻机器学习。

主题
人工智能
生成式 AI

通过这些课程学习 AI!

课程

使用 LangGraph 构建多智能体系统

2 小时 45 分钟
8.8K
通过在 LangGraph 框架中应用新兴的 agentic 设计模式,构建强大的多智能体系统。
查看详情Right Arrow
开始课程
查看更多Right Arrow