fix(voxtral): Audio als temp-WAV-Pfad an Processor (statt rohem Array)
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 <noreply@anthropic.com>
This commit is contained in:
+25
-10
@@ -29,11 +29,13 @@ import base64
|
|||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
import tempfile
|
||||||
import time
|
import time
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
import soundfile as sf
|
||||||
import websockets
|
import websockets
|
||||||
|
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
@@ -102,20 +104,33 @@ class VoxtralRunner:
|
|||||||
logger.info("Voxtral geladen in %.1fs", time.time() - t0)
|
logger.info("Voxtral geladen in %.1fs", time.time() - t0)
|
||||||
|
|
||||||
def _transcribe_blocking(self, audio_f32: np.ndarray, language: str) -> str:
|
def _transcribe_blocking(self, audio_f32: np.ndarray, language: str) -> str:
|
||||||
# ⚠️ VERIFY: exakte Voxtral-Transformers-API gegen die HF-Modelcard.
|
|
||||||
import torch
|
import torch
|
||||||
proc, model = self.processor, self.model
|
proc, model = self.processor, self.model
|
||||||
if proc is None or model is None or audio_f32.size == 0:
|
if proc is None or model is None or audio_f32.size == 0:
|
||||||
return ""
|
return ""
|
||||||
inputs = proc.apply_transcription_request(
|
# VoxtralProcessor verlangt bei rohen Arrays ein 'format'. Robuster:
|
||||||
language=language, audio=audio_f32, model_id=VOXTRAL_MODEL, sampling_rate=16000,
|
# in ein temp-WAV schreiben und den PFAD uebergeben — der Processor liest
|
||||||
)
|
# Format + Samplerate selbst, kein 'format'-Argument noetig.
|
||||||
inputs = inputs.to(VOXTRAL_DEVICE, dtype=torch.bfloat16)
|
wav_path = None
|
||||||
with torch.no_grad():
|
try:
|
||||||
outputs = model.generate(**inputs, max_new_tokens=512)
|
with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tf:
|
||||||
trimmed = outputs[:, inputs.input_ids.shape[1]:]
|
wav_path = tf.name
|
||||||
text = proc.batch_decode(trimmed, skip_special_tokens=True)
|
sf.write(wav_path, audio_f32, 16000, subtype="PCM_16")
|
||||||
return (text[0] if text else "").strip()
|
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:
|
async def transcribe(self, audio_f32: np.ndarray, language: str) -> str:
|
||||||
loop = asyncio.get_running_loop()
|
loop = asyncio.get_running_loop()
|
||||||
|
|||||||
Reference in New Issue
Block a user