fix: 修复按能力默认模型/批量测试的路由被 /{id}/test-connection 路径参数拦截导致 404 模型不存在

This commit is contained in:
qyyfw committed 2026-07-10 20:48:38 +08:00
1 parent 4c372746d5
commit 363ef7d7b6
1 file changed
+132 -128
+132 -128
View File
@@ -487,6 +487,69 @@ async def create_model(
return {"message": "模型已创建", "id": model.id}
# ============================================================
# 按能力默认模型(必须定义在 /{id} 路由之前,避免被路径参数拦截)
# ============================================================
@router.get("/capability-defaults")
async def get_capability_defaults_api(
admin_user=Depends(get_current_admin),
db: Session = Depends(get_db),
):
"""获取每个能力当前配置的默认模型,以及可选模型列表"""
defaults = get_capability_defaults(db)
models = db.query(AIModel).filter(AIModel.is_enabled == True).all()
model_list = [{
"id": m.id,
"name": m.name,
"display_name": getattr(m, "display_name", None) or m.name,
"provider_name": (
db.query(ModelProvider).filter(ModelProvider.id == m.provider_id).first().name
if m.provider_id else ""
),
"capabilities": m.capabilities or [],
} for m in models]
return {
"capabilities": [
{**c, "color": CAPABILITY_COLORS.get(c["id"], "#6B7280")}
for c in CAPABILITY_TYPES
],
"models": model_list,
"defaults": defaults,
}
class CapabilityDefaultRequest(BaseModel):
capability: str
model_id: Optional[str] = None
@router.put("/capability-defaults")
async def set_capability_default_api(
data: CapabilityDefaultRequest,
admin_user=Depends(get_current_admin),
db: Session = Depends(get_db),
):
"""为某个能力设置 / 清除默认模型"""
valid = {c["id"] for c in CAPABILITY_TYPES}
if data.capability not in valid:
raise HTTPException(status_code=400, detail=f"无效的能力类型: {data.capability}")
if data.model_id:
model = db.query(AIModel).filter(AIModel.id == data.model_id).first()
if not model:
raise HTTPException(status_code=404, detail="模型不存在")
updated = set_capability_default(db, data.capability, data.model_id)
LogService.log_audit(
admin_id=admin_user.id,
admin_name=admin_user.username,
action="set_capability_default",
target_type="model_capability",
target_id=data.capability,
detail=f"设置能力 {data.capability} 的默认模型为 {data.model_id or '(清除)'}",
)
return {"message": "已更新能力默认模型", "defaults": updated}
@router.put("/{id}")
async def update_model(
id: str,
@@ -640,64 +703,9 @@ async def get_model_stats(
# ============================================================
# 按能力指定默认模型(供技能 / 应用 / IM Bot 自动匹配)
# ============================================================
@router.get("/capability-defaults")
async def get_capability_defaults_api(
admin_user=Depends(get_current_admin),
db: Session = Depends(get_db),
):
"""获取每个能力当前配置的默认模型,以及可选模型列表"""
defaults = get_capability_defaults(db)
models = db.query(AIModel).filter(AIModel.is_enabled == True).all()
model_list = [{
"id": m.id,
"name": m.name,
"display_name": getattr(m, "display_name", None) or m.name,
"provider_name": (
db.query(ModelProvider).filter(ModelProvider.id == m.provider_id).first().name
if m.provider_id else ""
),
"capabilities": m.capabilities or [],
} for m in models]
return {
"capabilities": [
{**c, "color": CAPABILITY_COLORS.get(c["id"], "#6B7280")}
for c in CAPABILITY_TYPES
],
"models": model_list,
"defaults": defaults,
}
# (按能力默认模型路由已移至 /{id} 路由之前,避免路径参数冲突)
class CapabilityDefaultRequest(BaseModel):
capability: str
model_id: Optional[str] = None
@router.put("/capability-defaults")
async def set_capability_default_api(
data: CapabilityDefaultRequest,
admin_user=Depends(get_current_admin),
db: Session = Depends(get_db),
):
"""为某个能力设置 / 清除默认模型"""
valid = {c["id"] for c in CAPABILITY_TYPES}
if data.capability not in valid:
raise HTTPException(status_code=400, detail=f"无效的能力类型: {data.capability}")
if data.model_id:
model = db.query(AIModel).filter(AIModel.id == data.model_id).first()
if not model:
raise HTTPException(status_code=404, detail="模型不存在")
updated = set_capability_default(db, data.capability, data.model_id)
LogService.log_audit(
admin_id=admin_user.id,
admin_name=admin_user.username,
action="set_capability_default",
target_type="model_capability",
target_id=data.capability,
detail=f"设置能力 {data.capability} 的默认模型为 {data.model_id or '(清除)'}",
)
return {"message": "已更新能力默认模型", "defaults": updated}
# ============================================================
@@ -752,6 +760,73 @@ def _build_api_base(provider, ai_model):
return api_key, base_url
# ============================================================
# 批量连接测试(必须定义在 /{model_id}/test-connection 之前,避免被路径参数拦截)
# ============================================================
@router.post("/test-all")
async def test_all_models(
admin_user=Depends(get_current_admin),
db: Session = Depends(get_db),
):
"""批量测试所有已启用模型的连接状态"""
import asyncio
models = db.query(AIModel).filter(AIModel.is_enabled == True).all()
results = []
for m in models:
provider = db.query(ModelProvider).filter(ModelProvider.id == m.provider_id).first()
if not provider:
results.append({
"model_id": m.id,
"model_name": m.name,
"display_name": m.display_name or m.name,
"success": False,
"message": "供应商不存在",
"latency_ms": None,
"model_type": "unknown",
})
continue
# 复用 test_model_connection 逻辑
try:
result = await test_model_connection(m.id, admin_user, db)
if isinstance(result, dict):
result["model_id"] = m.id
result["model_name"] = m.name
result["display_name"] = m.display_name or m.name
results.append(result)
else:
results.append({
"model_id": m.id,
"model_name": m.name,
"display_name": m.display_name or m.name,
"success": False,
"message": "测试返回异常",
"latency_ms": None,
"model_type": "unknown",
})
except Exception as e:
results.append({
"model_id": m.id,
"model_name": m.name,
"display_name": m.display_name or m.name,
"success": False,
"message": f"测试异常: {str(e)}",
"latency_ms": None,
"model_type": "unknown",
})
success_count = sum(1 for r in results if r.get("success"))
return {
"total": len(results),
"success": success_count,
"failed": len(results) - success_count,
"results": results,
}
@router.post("/{model_id}/test-connection")
async def test_model_connection(
model_id: str,
@@ -1104,76 +1179,8 @@ def _build_error_response(resp, latency, model_type):
}
@router.post("/test-all")
async def test_all_models(
admin_user=Depends(get_current_admin),
db: Session = Depends(get_db),
):
"""批量测试所有已启用模型的连接状态"""
import asyncio
models = db.query(AIModel).filter(AIModel.is_enabled == True).all()
results = []
for m in models:
provider = db.query(ModelProvider).filter(ModelProvider.id == m.provider_id).first()
if not provider:
results.append({
"model_id": m.id,
"model_name": m.name,
"display_name": m.display_name or m.name,
"success": False,
"message": "供应商不存在",
"latency_ms": None,
"model_type": "unknown",
})
continue
# 复用 test_model_connection 逻辑
try:
result = await test_model_connection(m.id, admin_user, db)
if isinstance(result, dict):
result["model_id"] = m.id
result["model_name"] = m.name
result["display_name"] = m.display_name or m.name
results.append(result)
else:
results.append({
"model_id": m.id,
"model_name": m.name,
"display_name": m.display_name or m.name,
"success": False,
"message": "测试返回异常",
"latency_ms": None,
"model_type": "unknown",
})
except Exception as e:
results.append({
"model_id": m.id,
"model_name": m.name,
"display_name": m.display_name or m.name,
"success": False,
"message": f"测试异常: {str(e)}",
"latency_ms": None,
"model_type": "unknown",
})
success_count = sum(1 for r in results if r.get("success"))
return {
"total": len(results),
"success": success_count,
"failed": len(results) - success_count,
"results": results,
}
timeout: int = 60
status: str = "paid"
price_per_million_tokens: float = 0.0
is_enabled: bool = True
class UpdateModelRequest(BaseModel):
"""更新模型请求(保留兼容,实际更新使用 ModelUpdateRequest)"""
name: Optional[str] = None
api_key: Optional[str] = None
endpoint: Optional[str] = None
@@ -1183,6 +1190,3 @@ class UpdateModelRequest(BaseModel):
price_per_million_tokens: Optional[float] = None
is_enabled: Optional[bool] = None
from typing import Optional