55 lines
1.6 KiB
Python
55 lines
1.6 KiB
Python
from __future__ import annotations
|
||
|
||
import logging
|
||
from typing import Optional
|
||
|
||
import numpy as np
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
|
||
class ASRService:
|
||
def __init__(self) -> None:
|
||
self._model = None
|
||
self._post = None
|
||
self._ready = False
|
||
self._attempted = False
|
||
self._init_error: Optional[str] = None
|
||
|
||
def _ensure_loaded(self) -> None:
|
||
if self._ready or self._attempted:
|
||
return
|
||
self._attempted = True
|
||
try:
|
||
from funasr import AutoModel
|
||
from funasr.utils.postprocess_utils import rich_transcription_postprocess
|
||
|
||
self._model = AutoModel(
|
||
model="FunAudioLLM/SenseVoiceSmall",
|
||
device="cuda:0",
|
||
hub="hf",
|
||
)
|
||
self._post = rich_transcription_postprocess
|
||
self._ready = True
|
||
except Exception as exc: # pragma: no cover
|
||
self._init_error = str(exc)
|
||
logger.warning("ASR fallback mode: %s", exc)
|
||
|
||
async def transcribe(self, audio_16k: np.ndarray) -> str:
|
||
self._ensure_loaded()
|
||
if self._ready and self._model is not None and self._post is not None:
|
||
res = self._model.generate(
|
||
input=audio_16k,
|
||
cache={},
|
||
language="zh",
|
||
use_itn=True,
|
||
)
|
||
return self._post(res[0]["text"])
|
||
|
||
# Fallback for initial bring-up
|
||
return "(ASR降级)语音已接收"
|
||
|
||
@property
|
||
def health(self) -> dict:
|
||
return {"ready": self._ready, "attempted": self._attempted, "error": self._init_error}
|