From 3324d39d50aa7806d77750c9bbb751f9f109d10b Mon Sep 17 00:00:00 2001 From: duffyduck Date: Sat, 15 Aug 2026 11:29:51 +0200 Subject: [PATCH] fix(voxtral): Audio als temp-WAV-Pfad an Processor (statt rohem Array) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VoxtralProcessor.apply_transcription_request verlangt bei rohen Arrays ein 'format'. Fix: Buffer in ein temp-WAV (PCM_16, 16kHz) schreiben und den Pfad uebergeben — Processor liest Format+Samplerate selbst. Temp-Datei wird nach dem Transkribieren geloescht. Co-Authored-By: Claude Opus 4.8 --- xtts/voxtral/bridge.py | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/xtts/voxtral/bridge.py b/xtts/voxtral/bridge.py index 0341970..809db5b 100644 --- a/xtts/voxtral/bridge.py +++ b/xtts/voxtral/bridge.py @@ -29,11 +29,13 @@ import base64 import json import logging import os +import tempfile import time from dataclasses import dataclass, field from typing import Optional import numpy as np +import soundfile as sf import websockets logging.basicConfig( @@ -102,20 +104,33 @@ class VoxtralRunner: logger.info("Voxtral geladen in %.1fs", time.time() - t0) def _transcribe_blocking(self, audio_f32: np.ndarray, language: str) -> str: - # ⚠️ VERIFY: exakte Voxtral-Transformers-API gegen die HF-Modelcard. import torch proc, model = self.processor, self.model if proc is None or model is None or audio_f32.size == 0: return "" - inputs = proc.apply_transcription_request( - language=language, audio=audio_f32, model_id=VOXTRAL_MODEL, sampling_rate=16000, - ) - inputs = inputs.to(VOXTRAL_DEVICE, dtype=torch.bfloat16) - with torch.no_grad(): - outputs = model.generate(**inputs, max_new_tokens=512) - trimmed = outputs[:, inputs.input_ids.shape[1]:] - text = proc.batch_decode(trimmed, skip_special_tokens=True) - return (text[0] if text else "").strip() + # VoxtralProcessor verlangt bei rohen Arrays ein 'format'. Robuster: + # in ein temp-WAV schreiben und den PFAD uebergeben — der Processor liest + # Format + Samplerate selbst, kein 'format'-Argument noetig. + wav_path = None + try: + with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tf: + wav_path = tf.name + sf.write(wav_path, audio_f32, 16000, subtype="PCM_16") + inputs = proc.apply_transcription_request( + language=language, audio=wav_path, model_id=VOXTRAL_MODEL, + ) + inputs = inputs.to(VOXTRAL_DEVICE, dtype=torch.bfloat16) + with torch.no_grad(): + outputs = model.generate(**inputs, max_new_tokens=512) + trimmed = outputs[:, inputs.input_ids.shape[1]:] + text = proc.batch_decode(trimmed, skip_special_tokens=True) + return (text[0] if text else "").strip() + finally: + if wav_path: + try: + os.unlink(wav_path) + except Exception: + pass async def transcribe(self, audio_f32: np.ndarray, language: str) -> str: loop = asyncio.get_running_loop()