fix: 修复按能力默认模型/批量测试的路由被 /{id}/test-connection 路径参数拦截导致 404 模型不存在
This commit is contained in:
1 parent
4c372746d5
commit
363ef7d7b6
1 file changed
+132
-128
@@ -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
|
||||
|
||||
Reference in new issue
Block a user