mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-22 07:03:53 +08:00
Merge pull request #3255 from LauraGPT/funasr-language-option
fix: allow configuring FunASR recognition language
This commit is contained in:
@@ -0,0 +1,9 @@
|
|||||||
|
-- Add language configuration for local FunASR ASR.
|
||||||
|
UPDATE `ai_model_provider`
|
||||||
|
SET `fields` = '[{"key":"model_dir","label":"模型目录","type":"string"},{"key":"output_dir","label":"输出目录","type":"string"},{"key":"language","label":"识别语言","type":"string","default":"auto"}]'
|
||||||
|
WHERE `id` = 'SYSTEM_ASR_FunASR';
|
||||||
|
|
||||||
|
UPDATE `ai_model_config`
|
||||||
|
SET `config_json` = JSON_SET(`config_json`, '$.language', 'auto')
|
||||||
|
WHERE `id` = 'ASR_FunASR'
|
||||||
|
AND JSON_EXTRACT(`config_json`, '$.language') IS NULL;
|
||||||
Executable → Regular
+7
@@ -690,3 +690,10 @@ databaseChangeLog:
|
|||||||
- sqlFile:
|
- sqlFile:
|
||||||
encoding: utf8
|
encoding: utf8
|
||||||
path: classpath:db/changelog/202606261131.sql
|
path: classpath:db/changelog/202606261131.sql
|
||||||
|
- changeSet:
|
||||||
|
id: 202606301405
|
||||||
|
author: LauraGPT
|
||||||
|
changes:
|
||||||
|
- sqlFile:
|
||||||
|
encoding: utf8
|
||||||
|
path: classpath:db/changelog/202606301405.sql
|
||||||
|
|||||||
@@ -360,6 +360,9 @@ ASR:
|
|||||||
type: fun_local
|
type: fun_local
|
||||||
model_dir: models/SenseVoiceSmall
|
model_dir: models/SenseVoiceSmall
|
||||||
output_dir: tmp/
|
output_dir: tmp/
|
||||||
|
# 识别语种:auto 自动检测;如需限制只识别中文可设为 zh,避免中文短句误判为韩文等。
|
||||||
|
# SenseVoice 支持 zh、en、ja、ko、yue 等语种标记。
|
||||||
|
language: auto
|
||||||
FunASRServer:
|
FunASRServer:
|
||||||
# 独立部署FunASR,使用FunASR的API服务,只需要五句话
|
# 独立部署FunASR,使用FunASR的API服务,只需要五句话
|
||||||
# 第一句:mkdir -p ./funasr-runtime-resources/models
|
# 第一句:mkdir -p ./funasr-runtime-resources/models
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ class ASRProvider(ASRProviderBase):
|
|||||||
self.interface_type = InterfaceType.LOCAL
|
self.interface_type = InterfaceType.LOCAL
|
||||||
self.model_dir = config.get("model_dir")
|
self.model_dir = config.get("model_dir")
|
||||||
self.output_dir = config.get("output_dir") # 修正配置键名
|
self.output_dir = config.get("output_dir") # 修正配置键名
|
||||||
|
self.language = config.get("language", "auto")
|
||||||
self.delete_audio_file = delete_audio_file
|
self.delete_audio_file = delete_audio_file
|
||||||
|
|
||||||
# 确保输出目录存在
|
# 确保输出目录存在
|
||||||
@@ -80,7 +81,7 @@ class ASRProvider(ASRProviderBase):
|
|||||||
self.model.generate,
|
self.model.generate,
|
||||||
input=artifacts.pcm_bytes,
|
input=artifacts.pcm_bytes,
|
||||||
cache={},
|
cache={},
|
||||||
language="auto",
|
language=self.language,
|
||||||
use_itn=True,
|
use_itn=True,
|
||||||
batch_size_s=60,
|
batch_size_s=60,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,87 @@
|
|||||||
|
import asyncio
|
||||||
|
import importlib
|
||||||
|
import sys
|
||||||
|
import types
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
def install_fakes(monkeypatch):
|
||||||
|
class Logger:
|
||||||
|
def bind(self, **_kwargs):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def debug(self, *_args, **_kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def error(self, *_args, **_kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def info(self, *_args, **_kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def warning(self, *_args, **_kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
logger_module = types.ModuleType("config.logger")
|
||||||
|
logger_module.setup_logging = lambda: Logger()
|
||||||
|
config_module = types.ModuleType("config")
|
||||||
|
config_module.__path__ = []
|
||||||
|
monkeypatch.setitem(sys.modules, "config", config_module)
|
||||||
|
monkeypatch.setitem(sys.modules, "config.logger", logger_module)
|
||||||
|
|
||||||
|
psutil_module = types.ModuleType("psutil")
|
||||||
|
psutil_module.virtual_memory = lambda: types.SimpleNamespace(total=4 * 1024 * 1024 * 1024)
|
||||||
|
monkeypatch.setitem(sys.modules, "psutil", psutil_module)
|
||||||
|
|
||||||
|
class Base:
|
||||||
|
pass
|
||||||
|
|
||||||
|
base_module = types.ModuleType("core.providers.asr.base")
|
||||||
|
base_module.ASRProviderBase = Base
|
||||||
|
monkeypatch.setitem(sys.modules, "core.providers.asr.base", base_module)
|
||||||
|
|
||||||
|
dto_module = types.ModuleType("core.providers.asr.dto.dto")
|
||||||
|
dto_module.InterfaceType = types.SimpleNamespace(LOCAL="local")
|
||||||
|
monkeypatch.setitem(sys.modules, "core.providers.asr.dto.dto", dto_module)
|
||||||
|
|
||||||
|
utils_module = types.ModuleType("core.providers.asr.utils")
|
||||||
|
utils_module.lang_tag_filter = lambda text: {"content": text}
|
||||||
|
monkeypatch.setitem(sys.modules, "core.providers.asr.utils", utils_module)
|
||||||
|
|
||||||
|
class FakeAutoModel:
|
||||||
|
last_instance = None
|
||||||
|
|
||||||
|
def __init__(self, **_kwargs):
|
||||||
|
self.generate_kwargs = None
|
||||||
|
FakeAutoModel.last_instance = self
|
||||||
|
|
||||||
|
def generate(self, **kwargs):
|
||||||
|
self.generate_kwargs = kwargs
|
||||||
|
return [{"text": "你好"}]
|
||||||
|
|
||||||
|
funasr_module = types.ModuleType("funasr")
|
||||||
|
funasr_module.AutoModel = FakeAutoModel
|
||||||
|
monkeypatch.setitem(sys.modules, "funasr", funasr_module)
|
||||||
|
return FakeAutoModel
|
||||||
|
|
||||||
|
|
||||||
|
def test_fun_local_passes_configured_language_to_funasr_generate(tmp_path, monkeypatch):
|
||||||
|
server_root = Path(__file__).resolve().parents[1]
|
||||||
|
monkeypatch.syspath_prepend(str(server_root))
|
||||||
|
fake_model = install_fakes(monkeypatch)
|
||||||
|
monkeypatch.delitem(sys.modules, "core.providers.asr.fun_local", raising=False)
|
||||||
|
module = importlib.import_module("core.providers.asr.fun_local")
|
||||||
|
|
||||||
|
provider = module.ASRProvider(
|
||||||
|
{"model_dir": "models/SenseVoiceSmall", "output_dir": str(tmp_path), "language": "zh"},
|
||||||
|
delete_audio_file=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
artifacts = types.SimpleNamespace(pcm_bytes=b"\0\0", file_path=str(tmp_path / "audio.wav"))
|
||||||
|
text, audio_path = asyncio.run(
|
||||||
|
provider.speech_to_text([], "session-1", audio_format="pcm", artifacts=artifacts)
|
||||||
|
)
|
||||||
|
|
||||||
|
assert text == {"content": "你好"}
|
||||||
|
assert audio_path == artifacts.file_path
|
||||||
|
assert fake_model.last_instance.generate_kwargs["language"] == "zh"
|
||||||
Reference in New Issue
Block a user