feat: enable local docker demo mode
Some checks failed
Build and Push Docker Images / changes (push) Has been cancelled
Build and Push Docker Images / build-backend (push) Has been cancelled
Build and Push Docker Images / build-frontend (push) Has been cancelled
Build and Push Docker Images / build-admin-frontend (push) Has been cancelled
Some checks failed
Build and Push Docker Images / changes (push) Has been cancelled
Build and Push Docker Images / build-backend (push) Has been cancelled
Build and Push Docker Images / build-frontend (push) Has been cancelled
Build and Push Docker Images / build-admin-frontend (push) Has been cancelled
This commit is contained in:
@@ -33,14 +33,13 @@ class RoutingStrategy(str, Enum):
|
||||
ROUND_ROBIN = "round_robin" # 轮询
|
||||
|
||||
|
||||
# 默认配置映射(当 DB 无配置时使用)
|
||||
# 默认配置映射(当 DB 无配置时使用)
|
||||
# 这是“代码级”的默认策略,对应 .env 为空的情况
|
||||
DEFAULT_PROVIDERS: dict[ProviderType, list[str]] = {
|
||||
"text": ["gemini", "openai"],
|
||||
"image": ["cqtai"],
|
||||
"tts": ["minimax", "elevenlabs", "edge_tts"],
|
||||
"storybook": ["gemini"],
|
||||
"storybook": ["storybook_primary"],
|
||||
}
|
||||
|
||||
# API Key 映射:adapter_name -> settings 属性名
|
||||
@@ -88,6 +87,13 @@ def _get_api_key(config_ref: str | None, adapter_name: str) -> str:
|
||||
def _get_default_config(adapter_name: str) -> AdapterConfig | None:
|
||||
"""获取适配器的默认配置(无 DB 记录时使用)。返回 None 表示未知适配器。"""
|
||||
|
||||
if adapter_name == "demo":
|
||||
return AdapterConfig(
|
||||
api_key="",
|
||||
model="demo",
|
||||
timeout_ms=1000,
|
||||
)
|
||||
|
||||
# --- Text Defaults ---
|
||||
if adapter_name in ("gemini", "text_primary"):
|
||||
return AdapterConfig(
|
||||
@@ -103,7 +109,7 @@ def _get_default_config(adapter_name: str) -> AdapterConfig | None:
|
||||
)
|
||||
|
||||
# --- Image Defaults ---
|
||||
if adapter_name in ("cqtai"):
|
||||
if adapter_name == "cqtai":
|
||||
return AdapterConfig(
|
||||
api_key=getattr(settings, "cqtai_api_key", ""),
|
||||
model=settings.image_model or "nano-banana-pro",
|
||||
@@ -194,8 +200,12 @@ async def _get_providers_with_config(
|
||||
"text": settings.text_providers,
|
||||
"image": settings.image_providers,
|
||||
"tts": settings.tts_providers,
|
||||
"storybook": settings.storybook_providers,
|
||||
}
|
||||
names = settings_map.get(provider_type) or DEFAULT_PROVIDERS[provider_type]
|
||||
if settings.enable_demo_providers and "demo" not in names:
|
||||
names = ["demo", *names]
|
||||
|
||||
result = []
|
||||
for name in names:
|
||||
config = _get_default_config(name)
|
||||
@@ -273,12 +283,17 @@ async def _route_with_failover(
|
||||
# 按策略排序
|
||||
sorted_providers = _sort_by_strategy(providers, strategy, provider_type)
|
||||
|
||||
# 如果有 db 会话,过滤掉熔断的供应商
|
||||
# 如果有 db 会话,过滤掉后台管理台中已熔断的供应商。
|
||||
# .env/default provider 没有 providers 表记录,不能写入带外键的健康表。
|
||||
if db:
|
||||
healthy_providers = []
|
||||
for item in sorted_providers:
|
||||
name, config, db_provider = item
|
||||
provider_id = db_provider.id if db_provider else name
|
||||
if db_provider is None:
|
||||
healthy_providers.append(item)
|
||||
continue
|
||||
|
||||
provider_id = db_provider.id
|
||||
if await health_checker.is_healthy(db, provider_id):
|
||||
healthy_providers.append(item)
|
||||
else:
|
||||
@@ -295,7 +310,7 @@ async def _route_with_failover(
|
||||
errors.append(f"{name}: 适配器未注册")
|
||||
continue
|
||||
|
||||
provider_id = db_provider.id if db_provider else name
|
||||
provider_id = db_provider.id if db_provider else None
|
||||
|
||||
try:
|
||||
logger.debug(
|
||||
@@ -315,8 +330,8 @@ async def _route_with_failover(
|
||||
# 更新延迟缓存
|
||||
_latency_cache[name] = latency_ms
|
||||
|
||||
# 记录成功指标
|
||||
if db:
|
||||
# 记录成功指标。Provider 指标/健康表带外键,只记录后台管理台里的真实 provider。
|
||||
if db and db_provider and provider_id:
|
||||
await metrics_collector.record_call(
|
||||
db,
|
||||
provider_id=provider_id,
|
||||
@@ -326,16 +341,16 @@ async def _route_with_failover(
|
||||
)
|
||||
await health_checker.record_call_result(db, provider_id, success=True)
|
||||
|
||||
# 记录用户成本
|
||||
if user_id:
|
||||
await cost_tracker.record_cost(
|
||||
db,
|
||||
user_id=user_id,
|
||||
provider_name=name,
|
||||
capability=provider_type,
|
||||
estimated_cost=adapter.estimated_cost,
|
||||
provider_id=provider_id if db_provider else None,
|
||||
)
|
||||
# 记录用户成本;环境变量/default provider 没有 provider_id,保留 provider_name 即可。
|
||||
if db and user_id:
|
||||
await cost_tracker.record_cost(
|
||||
db,
|
||||
user_id=user_id,
|
||||
provider_name=name,
|
||||
capability=provider_type,
|
||||
estimated_cost=adapter.estimated_cost,
|
||||
provider_id=provider_id,
|
||||
)
|
||||
|
||||
logger.info(
|
||||
"provider_success",
|
||||
@@ -355,8 +370,8 @@ async def _route_with_failover(
|
||||
)
|
||||
errors.append(f"{name}: {exc}")
|
||||
|
||||
# 记录失败指标
|
||||
if db:
|
||||
# 记录失败指标。Provider 指标/健康表带外键,只记录后台管理台里的真实 provider。
|
||||
if db and db_provider and provider_id:
|
||||
await metrics_collector.record_call(
|
||||
db,
|
||||
provider_id=provider_id,
|
||||
|
||||
Reference in New Issue
Block a user