Use sliding window for realtime ASR preview

This commit is contained in:
Xulilong 2026-07-15 17:53:53 +08:00
parent 59c34ec1ff
commit 09885dd257
3 changed files with 18 additions and 6 deletions

View File

@ -98,6 +98,7 @@ VOICEPRINT_STORE=/data/asr_voiceprints.json
VOICEPRINT_MATCH_THRESHOLD=0.45
REALTIME_PARTIAL_MIN_SECONDS=1.5
REALTIME_PARTIAL_INTERVAL_SECONDS=2.0
REALTIME_PARTIAL_WINDOW_SECONDS=6.0
```
说明:

View File

@ -103,6 +103,7 @@ VOICEPRINT_STORE = os.environ.get("VOICEPRINT_STORE", "/tmp/asr_voiceprints.json
VOICEPRINT_MATCH_THRESHOLD = float(os.environ.get("VOICEPRINT_MATCH_THRESHOLD", "0.45"))
REALTIME_PARTIAL_INTERVAL_SECONDS = float(os.environ.get("REALTIME_PARTIAL_INTERVAL_SECONDS", "2.0"))
REALTIME_PARTIAL_MIN_SECONDS = float(os.environ.get("REALTIME_PARTIAL_MIN_SECONDS", "1.5"))
REALTIME_PARTIAL_WINDOW_SECONDS = float(os.environ.get("REALTIME_PARTIAL_WINDOW_SECONDS", "6.0"))
def _voiceprint_key(database_name: str, collection_name: str) -> str:
@ -261,6 +262,12 @@ def _write_pcm_wav(audio_bytes: bytes) -> str:
return tmp_path
def _recent_pcm(audio_chunks: list[bytes], window_seconds: float) -> bytes:
max_bytes = max(int(window_seconds * 32000), 32000)
audio_bytes = b"".join(audio_chunks)
return audio_bytes[-max_bytes:]
def _text_delta(previous: str, current: str) -> str:
previous = previous or ""
current = current or ""
@ -298,7 +305,7 @@ async def run_asr_websocket(websocket: WebSocket):
last_partial_at = now
partial_path = None
try:
partial_path = _write_pcm_wav(b"".join(audio_chunks))
partial_path = _write_pcm_wav(_recent_pcm(audio_chunks, REALTIME_PARTIAL_WINDOW_SECONDS))
result = await run_asr(partial_path, language="zh", response_format="json")
partial_text = result.get("text", "") if isinstance(result, dict) else ""
if partial_text and partial_text != last_partial_text:
@ -341,11 +348,14 @@ async def run_asr_websocket(websocket: WebSocket):
if isinstance(result, dict):
text = result.get("text", "")
await websocket.send_json({
"mode": "2pass-offline",
"text": text,
"is_final": True,
})
try:
await websocket.send_json({
"mode": "2pass-offline",
"text": text,
"is_final": True,
})
except Exception as e:
logger.warning(f"Skip final transcript because websocket is closed: {e}")
finally:
if tmp_path and os.path.exists(tmp_path):
os.unlink(tmp_path)

View File

@ -31,6 +31,7 @@ VOICEPRINT_STORE=/data/asr_voiceprints.json
VOICEPRINT_MATCH_THRESHOLD=0.45
REALTIME_PARTIAL_MIN_SECONDS=1.5
REALTIME_PARTIAL_INTERVAL_SECONDS=2.0
REALTIME_PARTIAL_WINDOW_SECONDS=6.0
# fastapi_wss legacy/local ASR-with-speaker helper
ASR_LOCAL_URL=http://asr-test:59805/asr