Files
ai-video-fullstack/backend/services/config_resolver.py
Xin Wang b444ea777c Implement knowledge base management and enhance assistant configuration
Add CRUD functionality for knowledge bases, including routes for listing, creating, updating, and deleting knowledge bases. Update the assistant model to include foreign key references to knowledge bases and modify the assistant configuration to handle external API keys securely. Refactor related services and routes to accommodate these changes, ensuring proper handling of credential resolution and configuration normalization.
2026-06-09 08:31:39 +08:00

73 lines
3.1 KiB
Python

"""assistant_id → 运行时配置(把真 key 在服务端组装好)。
浏览器只传 assistant_id;真 key 在这里从 provider_credentials 取出注入。
助手按 FK(*_credential_id)引用凭证;取不到则回退该 type 默认凭证,再回退 .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 _default_credential(
session: AsyncSession, type_: str
) -> ProviderCredential | None:
"""该 type 的默认凭证(is_default 优先,否则按 id 取第一条)。"""
stmt = (
select(ProviderCredential)
.where(ProviderCredential.type == type_)
.order_by(ProviderCredential.is_default.desc(), ProviderCredential.id.asc())
.limit(1)
)
return (await session.execute(stmt)).scalar_one_or_none()
async def _resolve(
session: AsyncSession, cred_id: str | None, type_: str
) -> ProviderCredential | None:
"""按 FK id 取凭证;id 为空或失效 → 回退该 type 默认。"""
if cred_id:
cred = await session.get(ProviderCredential, cred_id)
if cred:
return cred
return await _default_credential(session, type_)
async def resolve_runtime_config(
session: AsyncSession, assistant_id: str
) -> AssistantConfig:
"""加载助手 + 解析凭证,产出可直接交给管线的运行时配置(含真 key)。"""
assistant = await session.get(Assistant, assistant_id)
if assistant is None:
raise ValueError(f"助手不存在: {assistant_id}")
llm = await _resolve(session, assistant.llm_credential_id, "LLM")
stt = await _resolve(session, assistant.asr_credential_id, "ASR")
tts = await _resolve(session, assistant.tts_credential_id, "TTS")
realtime = await _resolve(session, assistant.realtime_credential_id, "Realtime")
cfg = assistant.config or {}
return AssistantConfig(
name=assistant.name,
greeting=assistant.greeting,
# 提示词/工作流类型把 prompt 放 config;外部类型由其平台编排,这里给个兜底
prompt=cfg.get("prompt") or "你是一个有帮助的助手。",
runtimeMode=assistant.runtime_mode, # type: ignore[arg-type]
enableInterrupt=assistant.enable_interrupt,
# 模型/音色:凭证的模型ID优先
model=(llm.model_id if llm else ""),
asr=(stt.model_id if stt else ""),
voice=cfg.get("voice", ""), # 音色不再是独立列,若 config 带则用,否则 .env 兜底
realtimeModel=(realtime.model_id if realtime else cfg.get("realtimeModel", "")),
# 运行时连接信息(真 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),
)