Ga naar hoofdinhoud

Mistrals Voxtral: een gids met demoproject

Leer hoe je Mistrals Voxtral Mini 3B‑model uitvoert met vLLM, een API opzet en een op Streamlit gebaseerde audio-samenvatter en Q&A‑app bouwt.
· 12 min lezen

Verken met AI

Mistral lanceerde onlangs zijn eerste open-source multimodale audiomodellen, Voxtral Small en Voxtral Mini, gebouwd op de Mistral 3B‑architectuur en specifiek geoptimaliseerd voor taken rond audiobegrip en transcriptie.

In deze blog richt ik me op Voxtral Mini 3B, een compact open‑source model ontworpen voor realtime audio-naar-tekst taken zoals transcriptie, samenvatting en Q&A. Dankzij het efficiënte formaat en ondersteuning voor redeneren met lange context is Voxtral Mini bijzonder krachtig in combinatie met high-throughput inference-frameworks zoals vLLM, wat het ideaal maakt voor snelle, offline audio-applicaties.

In deze tutorial laat ik je zien hoe je:

  • Voxtral Mini 3B uitvoert met vLLM op Colab Pro
  • Een via ngrok getunnelde API‑endpoint uitrolt om je model overal te kunnen benaderen
  • Een Streamlit‑gebaseerde audio-assistent bouwt die transcriptie, samenvatting en Q&A uitvoert op basis van ruwe audio-invoer

We houden onze lezers op de hoogte van het laatste AI‑nieuws met The Median, onze gratis vrijdagse nieuwsbrief met de belangrijkste verhalen van de week. Abonneer je en blijf scherp in een paar minuten per week:

Wat is Mistrals Voxtral?

Voxtral is Mistrals volledig open‑source audiomodelfamilie, ontworpen voor krachtige spraakbegrip. Voxtral is er in twee modelgroottes:

  • Voxtral Small: 24 B parameters, ideaal voor productie op schaal in de enterprise
  • Voxtral Mini: 3 B parameters, geoptimaliseerd om lokaal te draaien op edge‑apparaten

mistral's voxtral benchmarks

Bron: Mistral

Voxtral accepteert ruwe audio-invoer (zoals .wav of .mp3) en is getraind om efficiënt transcripties en samenvattingen te genereren uit gesproken content. Voxtral is een kleinere variant, geoptimaliseerd voor snelle inference en offline deployment.

Het volgt Mistrals modelformaat en is compatibel met high-throughput inference‑frameworks zoals vLLM, waardoor het een uitstekende keuze is voor realtime transcriptie of lichtgewicht spraaktoepassingen.

Voxtral Mini 3B uitvoeren met vLLM

In deze sectie laat ik je zien hoe je Voxtral Mini 3B serveert met vLLM op een Colab Pro met T4‑GPU ingeschakeld. vLLM is gekozen vanwege de high-throughput, lage-latentie serveercapaciteiten, ideaal voor modellen zoals Voxtral die snelle streamingantwoorden met audio-ondersteuning vereisen.

Daarnaast gebruiken we PyNGrok om de vLLM‑server via een publiek endpoint bloot te stellen, zodat deze toegankelijk is voor applicaties op je lokale machine.

Stap 1: Dependencies installeren

Laten we beginnen met het installeren van de dependencies in onze Colab‑omgeving. Voer de volgende opdracht uit in de Colab‑cel:

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

We beginnen met het installeren van de vereiste libraries met uv, een snellere Python‑pakketinstaller. Dit haalt de nightly‑versie van vllm[audio] op, die experimentele ondersteuning bevat voor audio‑taalmodellen zoals Voxtral. Als je uv niet in je omgeving hebt geïnstalleerd, installeer dan eerst uv met de volgende code:

!pip install uv

Stap 2: Mistral-Common installeren

Vervolgens installeren we het pakket mistral-common, dat essentiële utilities biedt om met Voxtral en andere modellen uit de Mistral‑familie te werken. Dit pakket bevat tokenizers die aansluiten op de officiële implementaties en Pydantic‑gebaseerde validatie voor berichtstructuren.

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

Het pakket mistral-common bevat utility‑modules voor Voxtral en andere modellen uit de Mistral‑familie. Het omvat tokenizers, getypeerde berichten in Pydantic‑formaten en audio‑hulpfuncties. Deze stap zorgt voor compatibiliteit met Voxtrals interne verwerking van audio-invoer en gestructureerde berichten.

Stap 3: VLLM instellen

Nu de basis‑dependencies voor Mistral klaar zijn, richten we vLLM in door de hoofdrepository te clonen.

Stap 3.1: De vLLM‑repository klonen

We clonen de officiële vLLM‑GitHub‑repository, die toegang geeft tot ingebouwde audio‑voorbeelden en dient als basis om offline of gehoste inference te starten.

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

Stap 3.2: Een voorbeeld van audio‑inference uitvoeren 

Laten we een snelle sanity check doen om te controleren of onze setup klopt.

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

Ik draaide het offline‑voorbeeld audio_language.py, dat audio‑taalinference uitvoert op twee vooraf gedefinieerde samples met het Voxtral‑model en bevestigt of audiodecodering en generatie correct werken.

Stap 4: PyGrok instellen

Nu vLLM is ingesteld, configureren we PyNGrok om de vLLM‑server op Colab via een publiek toegankelijke internet‑URL beschikbaar te maken.

  • Begin met het aanmaken van een gratis account op https://ngrok.com/
  • Scroll omlaag onder het tabblad Connect en kopieer de authenticatietoken (verborgen in de afbeelding hieronder) en sla deze op als secret in Colab Secrets.

NGrok Token

Vervolgens installeren we PyNGrok in de colab‑omgeving en stellen we de authenticatietoken in met de NGROK‑token die we eerder hebben gekopieerd. Werk je aan een prototype, dan kun je de token hier direct doorgeven.

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

Stap 5: Het model serven

Dit is de belangrijkste stap, waarin we het Voxtral Mini 3B‑model starten via vLLM. 

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

De code bevat een aantal belangrijke flags:

  • --tokenizer_mode mistral: Gebruikt de Mistral‑specifieke tokenizer voor nauwkeurige tokenisatie.
  • --config_format mistral en --load_format mistral: Deze flags zorgen ervoor dat zowel de modelconfiguratie als de gewichten in Mistrals aangepaste formaat worden geladen, zodat de compatibiliteit behouden blijft.
  • --max-model-len 4864: Stelt de maximale invoercontextlengte in op 4864 tokens.

Let op: laat deze cel actief, dit is een draaiende modelserver.

Stap 6: Het publieke NGrok‑endpoint ophalen

Zodra je vLLM‑server draait, voer je de volgende code regel voor regel uit in een Python‑terminal:

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

De bovenstaande code stelt het model bloot aan het internet op een tijdelijke publieke URL zoals:

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

Sla deze URL op; die gebruik je in de lokale config.py om verbinding te maken met het externe model. Beëindig na afloop de verbinding door:

ngrok.kill()

Een demo voor audiotranscriptie en samenvatting bouwen

In deze sectie bouwen we een Streamlit‑UI die:

  1. Audio als invoer neemt (upload door gebruiker)
  2. Deze naar het model stuurt via de vLLM‑server
  3. De transcriptie, samenvatting toont en de gebruiker vragen laat stellen

Stap 1: Dependencies instellen

Voordat we de app bouwen, definiëren we alle vereiste dependencies in een requirements.txt‑bestand. Dit zorgt voor consistente omgevingen bij lokale runs of Colab‑notebooks.

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 

Daarom hebben we elk van deze nodig:

  • streamlit: Deze library helpt bij het bouwen van de interactieve audio‑interface.
  • openai: maakt verbinding met de Voxtral‑compatibele vLLM‑server via de SDK van OpenAI.
  • mistral-common: Biedt Voxtral‑specifieke utilities zoals AudioChunk en TextChunk.
  • pyngrok: Stelt onze lokale vLLM‑server bloot aan het internet, zodat de Streamlit‑app er toegang toe heeft.
  • Pydub: Helpt bij het converteren van audiobestanden voor inference.
  • huggingface-hub en requests: Worden gebruikt voor het ophalen van model en config (indien nodig).

Stap 2: De omgevingsvariabele instellen

Om de configuratie overzichtelijk en draagbaar te houden, slaan we API‑gegevens op als omgevingsvariabelen. Je kunt ze definiëren in een .env‑bestand:

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

VOXTRAL_API_BASE moet wijzen naar je draaiende vLLM‑instantie, wat localhost kan zijn (http://localhost:8000) of een ngrok‑public endpoint zoals https://80xxxxxxxxxx.ngrok-free.app.

Let op: zorg dat je /v1 achter de API‑basis plakt voor OpenAI‑compatibiliteit.

Stap 3: Het config‑bestand instellen

Om je app modulair, eenvoudig aanpasbaar en klaar voor productie te maken, definiëren we een centrale configuratieklasse in config.py. Dit bestand beheert modelinstellingen, API‑toegang, ondersteunde audioformaten, talen en UI‑voorkeuren.

Stap 3.1: Omgevingsvariabelen laden

Voordat we de config‑klasse definiëren, laden we eventuele omgevingsvariabelen uit een .env‑bestand. Zo houd je gevoelige info buiten de code.

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

Deze snippet controleert of er een .env‑bestand in de hoofdmap staat. Zo ja, dan leest hij sleutel‑waardeparen en zet die als omgevingsvariabelen. Deze waarden zijn nu toegankelijk met os.getenv(), zodat secrets niet hardcoded in de app belanden.

Stap 3.2: De Config‑klasse definiëren

Nu bundelen we alle instellingen in een overzichtelijke Config‑klasse voor gemakkelijke toegang en hergebruik.

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) 

Samen fungeert deze Config‑klasse als het gecentraliseerde controlecentrum voor je Voxtral‑app. Of je nu modelparameters configureert, audioformaten beheert of het app‑thema instelt: deze opzet zorgt voor een nette abstractie, herbruikbaarheid en onderhoudbaarheid van de code.

De klasse bevat:

  • get_api_config()‑methode: Deze methode centraliseert alle API‑gerelateerde gegevens. Waar je app ook een call naar het Voxtral‑model maakt, je kunt simpelweg Config.get_api_config() gebruiken om alles in één keer op te halen.
  • validate_config()‑methode: Voor je inference start, kun je hiermee controleren of essentiële configuratiewaarden (zoals de basis‑URL) correct zijn ingesteld. Zo kun je problemen vroegtijdig opvangen en de gebruiker waarschuwen.
  • get_language_code()‑methode: Hiermee schakel je naadloos meertalige Q&A in door gebruiksvriendelijke talenamen uit de UI (bijv. “French”) te mappen naar gestandaardiseerde ISO‑taalcodes (bijv. “fr”). Als een niet‑ondersteunde taal wordt doorgegeven, retourneert deze veilig None.

Stap 4: De Streamlit‑app bouwen

We doorlopen elke sub‑stap die de interface en logica van de app opbouwt.

Stap 4.1: Lay‑out en styling instellen

In deze stap initialiseren we de Streamlit‑frontend, laden we dependencies en stellen we de CSS‑stijl in. Dit vormt de visuele en functionele basis van de app.

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)

In de bovenstaande Python‑ en CSS‑code:

  • Importeren we essentiële libraries voor UI, bestandsafhandeling en audio-/tekstberichtopmaak met Voxtrals mistral_common‑pakket.
  • Configureren we vervolgens de lay‑out van de Streamlit‑app: een interface met twee panelen en een standaard uitgevouwen zijbalk.
  • Tot slot injecteren we aangepaste CSS om verschillende UI‑onderdelen visueel te scheiden, zoals headers, audiosecties, chatballonnen en samenvattingsvakken. Dit verbetert de visuele hiërarchie van de app met opgemaakte titels, infoberichten en onderscheidende chatballonnen voor gebruiker vs. assistent.

Stap 4.2: Sessie en client initialiseren

Vervolgens zorgen we dat de app consistent werkt bij herladen door sessievariabelen en de client te initialiseren.

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

Deze code zet de interne status van de applicatie op en behandelt de verbinding met de Voxtral‑API‑server. Twee kernonderdelen:

  1. Sessie‑initialisatie: Zorgt dat gebruikersgegevens zoals transcripties, samenvattingen en geüploade audiobestanden correct blijven bestaan tijdens interacties en herladen.
  2. Client‑initialisatie: Maakt verbinding met het lokaal gehoste Voxtral Mini 3B‑model via het OpenAI‑compatibele endpoint dat door vLLM wordt blootgesteld (via Ngrok). Als de verbinding faalt, verschijnt er een foutmelding in de UI.

Stap 4.3: Audio chunking en realtime transcriptie

Deze stap verzorgt de kernlogica voor het voorbereiden van het audiobestand en het genereren van een transcriptie met 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

Er zijn hier twee belangrijke functies:

  1. Conversie naar audiochunk: Eerst converteren we het geüploade audiobestand naar het AudioChunk‑formaat, de vereiste invoer voor Voxtrals API.
  2. Streamingtranscriptie met voortgangsfeedback: We sturen de audio gestreamd naar het model (stream=True) en decoderen hem chunk‑voor‑chunk. Een voortgangsbalk werkt dynamisch bij terwijl tokens binnenkomen, zodat gebruikers realtime feedback krijgen over de voortgang van de transcriptie.

Stap 4.4: Samenvatting uit audio genereren

Deze stap stuurt de audio‑invoer samen met een tekstuele prompt naar het Voxtral‑model, dat een beknopte, gestructureerde samenvatting van de audiocontent retourneert.

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

De bovenstaande code gebruikt enkele kernmethoden en functies om een samenvatting te genereren uit de geüploade audio:

  • audio_chunk: Eerst converteren we het geüploade bestand naar een AudioChunk voor Voxtrals audioprocessing.
  • text_chunk: Vervolgens gebruiken we een tekstprompt om het model te instrueren de inhoud duidelijk en volledig samen te vatten.
  • UserMessage: Dit combineert de audio_chunk en text_chunk tot één multimodaal bericht in een OpenAI‑compatibel formaat. 
  • Response.choices[0].message.content: Dit object haalt de daadwerkelijke samenvattingstekst uit het antwoord van het model.

Stap 4.5: Meertalige Q&A over audio

Nu we de samenvatting hebben, stellen we gebruikers in staat om natuurlijke taalvragen te stellen over de geüploade audiocontent. Dit benut Voxtrals multimodale capaciteiten door audio met tekstprompts te combineren om contextbewuste antwoorden te genereren.

De volgende functie ondersteunt ook meertalige antwoorden door de prompt dynamisch aan te passen op basis van de geselecteerde taal.

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

Dit is wat er hier gebeurt:

  • De functie ask_question() laat gebruikers elke vraag stellen over de geüploade audio.
  • Ze begint met het converteren van het geüploade bestand naar een AudioChunk met de herbruikbare functie file_to_chunk(), zodat de audio in het door Voxtrals multimodale API verwachte formaat staat.
  • Vervolgens controleert ze de geselecteerde taal. Als het niet Engels is, wordt de vraag van de gebruiker voorafgegaan door een instructie om in de gewenste taal te antwoorden (bijv. Hindi of Spaans).
  • De vraag van de gebruiker wordt verpakt in een TextChunk, en zowel audio als tekst worden gebundeld in een multimodaal UserMessage.
  • We sturen dit bericht naar het model, samen met temperature‑ en top‑p‑waarden uit de configuratie om de generatiekwaliteit te sturen.
  • Het model retourneert vervolgens een enkel antwoord.

Stap 4.6: De zijbalk instellen

De zijbalk fungeert als controlepaneel waarmee gebruikers sessie‑instellingen beheren, de uitvoertaal selecteren, de verbinding met de Voxtral‑API testen en het antwoordgedrag van het model aanpassen via intuïtieve sliders.

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

Uitleg bij de bovenstaande code:

  • Zijbalk: Met st.sidebar openen we een inklapbare zijbalk waarin we configuratietools voor de app plaatsen.
  • Verbindingstest: Een knop “Test Connection” triggert de functie initialize_client(), die probeert verbinding te maken met de Voxtral‑API en succes of falen meldt met Streamlit‑alerts.
  • Taalkeuze: Een dropdown laat gebruikers een van de 12 ondersteunde talen kiezen. Deze keuze bepaalt later in welke taal het model antwoordt.
  • Modelparameters: Met een slider kan de gebruiker parameters sturen zoals:
    • temperature: Stuurt creativiteit. Lagere waarden maken antwoorden deterministischer, hogere waarden gevarieerder.
    • top_p: Stuurt nucleus sampling, wat de generatie beperkt tot de meest waarschijnlijke tokens.
  • Sessiereset: Met “Clear Session” reset je alle sessiestatusvariabelen en start je de app opnieuw.

Stap 4.7: Sectie voor uploaden en verwerken van audio

In deze sectie kunnen gebruikers audiobestanden uploaden (zoals .mp3, .wav, enz.), die tijdelijk worden opgeslagen. Na uploaden kunnen ze kiezen om de audio te transcriberen of een samenvatting op hoog niveau te genereren. 

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")

We hebben een modulaire structuur nodig voor eenvoudig uploaden, verwerken en het persistent opslaan van resultaten tijdens interacties. Zo heb ik het gedaan:

  • Bestandsuploader: Eerst hebben we een drag‑en‑drop uploader nodig die meerdere audioformaten accepteert zoals gedefinieerd in Config.SUPPORTED_AUDIO_FORMATS. Na uploaden wordt het bestand naar een tijdelijk bestand geschreven en opgeslagen in st.session_state.audio_file_path.
  • Client‑initialisatie: Er wordt een Voxtral‑compatibele client geïnitialiseerd om samenvatten en transcriberen mogelijk te maken.
  • Knoppen voor samenvatting en transcriptie: Vervolgens definiëren we twee knoppen:
    • Generate summary: Stuurt bij klikken de geüploade audio naar het model met een samenvattingsprompt. Er verschijnt een spinner en bij succes wordt de output opgeslagen in st.session_state.summary.
    • Transcribe audio: Stuurt het audiobestand naar de transcriptie‑endpoint. Realtime voortgang wordt getoond met een spinner en het resultaat wordt opgeslagen in st.session_state.transcription.
  • Tot slot worden beide resultaten weergegeven in een tekstvak.

Stap 4.8: Interactieve meertalige Q&A

Deze stap laat gebruikers vragen stellen over de geüploade audio in meerdere talen (bijv. Engels, Hindi, Spaans). De geselecteerde taal wordt gebruikt om het antwoord van het model te formatteren, en elk vraag‑antwoordpaar wordt opgeslagen in een door de sessie beheerde gespreksgeschiedenis en weergegeven met chatballonnen.

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)

Uitleg bij de bovenstaande code:

  • Ask Question‑knop: Een tekstveld laat gebruikers een vraag typen in de geselecteerde taal en op de knop Ask Question klikken. Na klikken wordt:
    • De Voxtral‑compatibele client geïnitialiseerd.
    • De vraag samen met de geüploade audio naar het model gestuurd.
    • Een spinner getoond terwijl je wacht op het antwoord van het model.
  • Afhandeling van antwoorden: Als er een antwoord binnenkomt, wordt het:
    • Opgeslagen in st.session_state.chat_history met een timestamp.
    • Weergegeven met rol‑specifieke opmaak met de eerdere aangepaste CSS (gebruiker vs. assistent).
    • Als het model faalt, verschijnt een duidelijke foutmelding.
  • Gespreksgeschiedenis: Als er eerdere Q&A‑paren zijn, worden die in omgekeerd chronologische volgorde getoond met een scheiding.

Stap 4.9: De app starten

Deze laatste stap brengt alle eerder gedefinieerde componenten samen, waaronder het initialiseren van de sessiestatus, het renderen van de zijbalk, het afhandelen van uploads, transcripties, samenvattingen en Q&A met een tweekoloms‑lay‑out.

Zodra de server draait en alle dependencies zijn geïnstalleerd, zorgt deze stap ervoor dat de app via Streamlit in de browser wordt bediend en klaar is voor interactie.

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() 

De functie main() fungeert als instappunt voor de app. Ze beheert de lay‑out, regelt het renderen en zorgt dat alle sessievariabelen en UI‑componenten correct zijn geïnitialiseerd. Dit is een samenvatting van wat de hierboven gedefinieerde functies doen:

  • init_session_state(): Bereidt standaardwaarden voor zoals transcription, summary en chat_history om de app‑status te behouden tijdens interacties.
  • render_sidebar(): Laadt configuratiewidgets zoals de taalselector, verbindingstest en modelparameters.
  • render_audio_processing(): Laat gebruikers audiobestanden uploaden en verwerken voor transcriptie en samenvatting.
  • render_qa_section(): Maakt ten slotte meertalig vraag‑en‑antwoord mogelijk op geüploade audio.

Als alles klaar is, start je de app met:

pip install -r requirements.txt

Zorg dat hij bereikbaar is via de URL die is opgegeven in VOXTRAL_API_BASE in je config.py. Zodra alle dependencies zijn geïnstalleerd, start je de Streamlit‑applicatie met de volgende opdracht in de terminal:

streamlit run app.py

Je browser opent de interface automatisch. De app is nu volledig functioneel met audio‑upload, realtime transcriptie, samenvattingen en meertalige Q&A, aangedreven door Voxtral Mini 3B.

Je vindt alle code die we hier hebben behandeld in deze GitHub‑repository die ik heb opgezet.

Conclusie

Voxtral Mini 3B is een efficiënt, open‑weight model voor spraaktranscriptie en ‑begrip. In deze tutorial hebben we het gedraaid met vLLM, een API opgezet en een audio‑samenvattingsapp gebouwd met Streamlit.

Of je nu een podcast‑samenvatter, vergaderassistent of spraakcommando‑app bouwt, Voxtral Mini kan dienen als fundament voor snelle en lokale audioredenatie.

Aashi Dutt

Auteur

Aashi Dutt

Ik ben een Google Developers Expert in ML (Gen AI), een Kaggle 3x Expert en een Women Techmakers Ambassador met meer dan 3 jaar ervaring in tech. In 2020 heb ik een healthtech-startup mee opgericht en ik volg een master computer science aan Georgia Tech, met als specialisatie machine learning.

Onderwerpen

Gerelateerd