- Introduce a new model structure for managing interface definitions and model resources, enhancing the backend's capability to handle various service integrations. - Update the Makefile to reflect changes in database seeding and resource management commands. - Remove the deprecated credentials management routes and replace them with a unified model registry API. - Modify existing routes and schemas to align with the new model structure, ensuring seamless integration with the frontend. - Enhance database seeding scripts to populate new model resources and their configurations. - Update README documentation to reflect the new architecture and usage instructions for model resources and interface definitions.
136 lines
5.7 KiB
Python
136 lines
5.7 KiB
Python
"""创建 STT / LLM / TTS 服务。
|
|
|
|
对应 dograh 的 service_factory.py,但只留一套国产栈(OpenAI 兼容),
|
|
按 interface_type 扩展时在这里加分支即可——这是未来接更多模型的唯一入口。
|
|
"""
|
|
|
|
import config
|
|
from loguru import logger
|
|
from models import AssistantConfig
|
|
|
|
from pipecat.services.openai.llm import OpenAILLMService
|
|
from pipecat.services.openai.stt import OpenAISTTService
|
|
from pipecat.services.openai.tts import VALID_VOICES, OpenAITTSService
|
|
from pipecat.transcriptions.language import Language
|
|
|
|
from services.pipecat.xfyun_asr import DEFAULT_XFYUN_ASR_URL, XfyunASRService
|
|
from services.pipecat.xfyun_config import websocket_url, xfyun_language, xfyun_speed
|
|
from services.pipecat.xfyun_super_tts import (
|
|
DEFAULT_XFYUN_SUPER_TTS_URL,
|
|
XfyunSuperTTSService,
|
|
)
|
|
from services.pipecat.xfyun_tts import DEFAULT_XFYUN_TTS_URL, XfyunTTSService
|
|
|
|
|
|
def _language(value: str) -> Language | None:
|
|
if not value:
|
|
return None
|
|
try:
|
|
return Language(value)
|
|
except ValueError:
|
|
logger.warning(f"忽略不支持的 ASR language: {value}")
|
|
return None
|
|
|
|
|
|
def create_stt(cfg: AssistantConfig):
|
|
"""SenseVoice / FunASR 等,走 OpenAI 兼容的 /v1/audio/transcriptions。
|
|
|
|
连接信息优先用 cfg(由 config_resolver 从 DB 注入),为空回退 .env 默认。
|
|
"""
|
|
if cfg.stt_interface_type == "xfyun-asr":
|
|
return XfyunASRService(
|
|
app_id=str(cfg.stt_secrets.get("appId") or ""),
|
|
api_key=str(cfg.stt_secrets.get("apiKey") or ""),
|
|
api_secret=str(cfg.stt_secrets.get("apiSecret") or ""),
|
|
url=websocket_url(cfg.stt_base_url, DEFAULT_XFYUN_ASR_URL),
|
|
language=xfyun_language(cfg.stt_language),
|
|
sample_rate=16000,
|
|
domain=str(cfg.stt_values.get("domain") or "iat"),
|
|
accent=str(cfg.stt_values.get("accent") or "mandarin"),
|
|
frame_size=int(cfg.stt_values.get("frameSize") or 1280),
|
|
dynamic_correction=bool(cfg.stt_values.get("dynamicCorrection", False)),
|
|
)
|
|
if cfg.stt_interface_type not in {"openai-asr", "dashscope-asr"}:
|
|
raise ValueError(f"不支持的 ASR 接口类型: {cfg.stt_interface_type}")
|
|
|
|
return OpenAISTTService(
|
|
api_key=cfg.stt_api_key or config.STT_API_KEY,
|
|
base_url=cfg.stt_base_url or config.STT_BASE_URL,
|
|
settings=OpenAISTTService.Settings(
|
|
model=cfg.asr or config.STT_MODEL,
|
|
language=_language(cfg.stt_language),
|
|
),
|
|
)
|
|
|
|
|
|
def create_llm(cfg: AssistantConfig):
|
|
"""DeepSeek 等,走 OpenAI 兼容的 /v1/chat/completions。"""
|
|
if cfg.llm_interface_type not in {"openai-llm", "dashscope-llm"}:
|
|
raise ValueError(f"不支持的 LLM 接口类型: {cfg.llm_interface_type}")
|
|
return OpenAILLMService(
|
|
api_key=cfg.llm_api_key or config.LLM_API_KEY,
|
|
base_url=cfg.llm_base_url or config.LLM_BASE_URL,
|
|
settings=OpenAILLMService.Settings(model=cfg.model or config.LLM_MODEL),
|
|
)
|
|
|
|
|
|
def create_tts(cfg: AssistantConfig):
|
|
"""CosyVoice 等,走 OpenAI 兼容的 /v1/audio/speech。"""
|
|
voice = cfg.voice or config.TTS_VOICE
|
|
if cfg.tts_interface_type == "xfyun-super-tts":
|
|
return XfyunSuperTTSService(
|
|
app_id=str(cfg.tts_secrets.get("appId") or ""),
|
|
api_key=str(cfg.tts_secrets.get("apiKey") or ""),
|
|
api_secret=str(cfg.tts_secrets.get("apiSecret") or ""),
|
|
voice=voice,
|
|
url=websocket_url(cfg.tts_base_url, DEFAULT_XFYUN_SUPER_TTS_URL),
|
|
sample_rate=16000,
|
|
source_sample_rate=int(cfg.tts_values.get("sourceSampleRate") or 24000),
|
|
speed=xfyun_speed(cfg.tts_speed),
|
|
volume=int(cfg.tts_values.get("volume") or 50),
|
|
pitch=int(cfg.tts_values.get("pitch") or 50),
|
|
oral_level=str(cfg.tts_values.get("oralLevel") or "mid"),
|
|
text_aggregation_mode=str(
|
|
cfg.tts_values.get("textAggregationMode") or "token"
|
|
),
|
|
)
|
|
if cfg.tts_interface_type == "xfyun-tts":
|
|
return XfyunTTSService(
|
|
app_id=str(cfg.tts_secrets.get("appId") or ""),
|
|
api_key=str(cfg.tts_secrets.get("apiKey") or ""),
|
|
api_secret=str(cfg.tts_secrets.get("apiSecret") or ""),
|
|
voice=voice,
|
|
url=websocket_url(cfg.tts_base_url, DEFAULT_XFYUN_TTS_URL),
|
|
sample_rate=16000,
|
|
source_sample_rate=int(cfg.tts_values.get("sourceSampleRate") or 16000),
|
|
speed=xfyun_speed(cfg.tts_speed),
|
|
volume=int(cfg.tts_values.get("volume") or 50),
|
|
pitch=int(cfg.tts_values.get("pitch") or 50),
|
|
push_stop_frames=True,
|
|
)
|
|
if cfg.tts_interface_type not in {"openai-tts", "dashscope-tts"}:
|
|
raise ValueError(f"不支持的 TTS 接口类型: {cfg.tts_interface_type}")
|
|
|
|
# Pipecat 默认只接受 OpenAI 官方音色。OpenAI 兼容服务常使用自定义 voice id,
|
|
# 注册为原样映射后仍由 OpenAI SDK 按字符串透传给供应商。
|
|
VALID_VOICES.setdefault(voice, voice)
|
|
return OpenAITTSService(
|
|
api_key=cfg.tts_api_key or config.TTS_API_KEY,
|
|
base_url=cfg.tts_base_url or config.TTS_BASE_URL,
|
|
settings=OpenAITTSService.Settings(
|
|
model=cfg.tts_model or config.TTS_MODEL,
|
|
voice=voice,
|
|
speed=cfg.tts_speed,
|
|
),
|
|
)
|
|
|
|
|
|
def create_services(cfg: AssistantConfig):
|
|
logger.info(
|
|
f"创建服务: stt={cfg.stt_interface_type}/{cfg.asr or config.STT_MODEL} "
|
|
f"llm={cfg.model or config.LLM_MODEL} "
|
|
f"tts={cfg.tts_interface_type}/{cfg.tts_model or config.TTS_MODEL} "
|
|
f"voice={cfg.voice or config.TTS_VOICE}"
|
|
)
|
|
return create_stt(cfg), create_llm(cfg), create_tts(cfg)
|