"""装配根:把配置变成可用的适配器。 **这是唯一允许同时知道「配置」与「具体供应商」的地方。** 其余模块只依赖抽象: 适配器通过构造参数拿配置(而非自己读环境变量),上层通过 `ProviderRegistry` 按 `provider_code` 拿适配器。新增一家供应商只需在此登记一行。 `app/providers/base.py`、`registry.py` 与 `app/domain/` 对具体供应商零依赖, 这一点由 `tests/test_layering.py` 自动守着——靠纪律守不住,靠测试才守得住。 """ from __future__ import annotations import logging from app.config import Settings from app.providers.base import GenerationProvider from app.providers.registry import ProviderRegistry from app.providers.volcengine.client import ArkClient from app.providers.volcengine.video import SeedanceVideoProvider log = logging.getLogger(__name__) def build_registry(settings: Settings) -> ProviderRegistry: """按配置装配所有可用的适配器。 **缺凭证的供应商被跳过而不是让装配失败**:本地只配了一家凭证时,服务仍应能 起来并提供其余能力与健康检查。真正的失败点在调用时——那时 `find()` 返回 None,调用方按「适配器不可用」处理,而不是把一个半死的实例放出去。 """ providers: list[GenerationProvider] = [] volcengine = settings.volcengine if volcengine.api_key: providers.append( SeedanceVideoProvider( ArkClient( api_key=volcengine.api_key, base_url=volcengine.base_url, timeout_sec=volcengine.timeout_sec, ), default_model=volcengine.video_model, task_expiry_sec=volcengine.task_expiry_sec, ) ) else: # 警告而非静默:这是最容易被忽略的配置缺失,而症状(任务永远排队) # 与它相隔很远。 log.warning("ARK_API_KEY 未配置,火山方舟视频适配器未装配") registry = ProviderRegistry(providers) log.info("已装配 %d 个生成适配器:%s", len(registry), sorted(registry.codes)) return registry