Initial commit: AI Video Assistant fullstack platform.
Add pipecat-based backend with WebRTC/WS voice routes, Next.js frontend, and Docker Compose orchestration. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
64
backend/services/config_resolver.py
Normal file
64
backend/services/config_resolver.py
Normal file
@@ -0,0 +1,64 @@
|
||||
"""assistant_id → 运行时配置(把真 key 在服务端组装好)。
|
||||
|
||||
浏览器只传 assistant_id;真 key 在这里从 provider_credentials 取出注入。
|
||||
取不到凭证记录时,降级用 .env 默认值(开发期零配置仍能跑)。
|
||||
"""
|
||||
|
||||
import config
|
||||
from db.models import Assistant, ProviderCredential
|
||||
from models import AssistantConfig
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
|
||||
async def _get_credential(
|
||||
session: AsyncSession, type_: str, name: str = ""
|
||||
) -> ProviderCredential | None:
|
||||
"""取某类(LLM/ASR/TTS)凭证:优先按资源名匹配,否则取该类默认。"""
|
||||
stmt = select(ProviderCredential).where(ProviderCredential.type == type_)
|
||||
if name:
|
||||
# 助手按资源名引用(如 model="DeepSeek-V3");命中则用它
|
||||
named = (
|
||||
await session.execute(stmt.where(ProviderCredential.name == name).limit(1))
|
||||
).scalar_one_or_none()
|
||||
if named:
|
||||
return named
|
||||
stmt = stmt.order_by(
|
||||
ProviderCredential.is_default.desc(), ProviderCredential.id.asc()
|
||||
).limit(1)
|
||||
return (await session.execute(stmt)).scalar_one_or_none()
|
||||
|
||||
|
||||
async def resolve_runtime_config(
|
||||
session: AsyncSession, assistant_id: str
|
||||
) -> AssistantConfig:
|
||||
"""加载助手 + 解析凭证,产出可直接交给管线的运行时配置(含真 key)。
|
||||
|
||||
type 映射:LLM→大模型, ASR→语音识别, TTS→语音合成。
|
||||
"""
|
||||
assistant = await session.get(Assistant, assistant_id)
|
||||
if assistant is None:
|
||||
raise ValueError(f"助手不存在: {assistant_id}")
|
||||
|
||||
llm = await _get_credential(session, "LLM", assistant.model)
|
||||
stt = await _get_credential(session, "ASR", assistant.asr)
|
||||
tts = await _get_credential(session, "TTS")
|
||||
|
||||
return AssistantConfig(
|
||||
name=assistant.name,
|
||||
greeting=assistant.greeting,
|
||||
prompt=assistant.prompt,
|
||||
runtimeMode=assistant.runtime_mode, # type: ignore[arg-type]
|
||||
enableInterrupt=assistant.enable_interrupt,
|
||||
# 模型/音色:凭证的模型ID优先,否则助手里填的
|
||||
model=(llm.model_id if llm else assistant.model),
|
||||
asr=(stt.model_id if stt else assistant.asr),
|
||||
voice=assistant.voice,
|
||||
# 运行时连接信息(真 key + url):凭证优先,否则 .env 兜底
|
||||
llm_api_key=(llm.api_key if llm else config.LLM_API_KEY),
|
||||
llm_base_url=(llm.api_url if llm else config.LLM_BASE_URL),
|
||||
stt_api_key=(stt.api_key if stt else config.STT_API_KEY),
|
||||
stt_base_url=(stt.api_url if stt else config.STT_BASE_URL),
|
||||
tts_api_key=(tts.api_key if tts else config.TTS_API_KEY),
|
||||
tts_base_url=(tts.api_url if tts else config.TTS_BASE_URL),
|
||||
)
|
||||
Reference in New Issue
Block a user