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}
|
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}")
|
@router.put("/{id}")
|
||||||
async def update_model(
|
async def update_model(
|
||||||
id: str,
|
id: str,
|
||||||
@@ -640,64 +703,9 @@ async def get_model_stats(
|
|||||||
# ============================================================
|
# ============================================================
|
||||||
# 按能力指定默认模型(供技能 / 应用 / IM Bot 自动匹配)
|
# 按能力指定默认模型(供技能 / 应用 / IM Bot 自动匹配)
|
||||||
# ============================================================
|
# ============================================================
|
||||||
|
# (按能力默认模型路由已移至 /{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}
|
|
||||||
|
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
@@ -752,6 +760,73 @@ def _build_api_base(provider, ai_model):
|
|||||||
return api_key, base_url
|
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")
|
@router.post("/{model_id}/test-connection")
|
||||||
async def test_model_connection(
|
async def test_model_connection(
|
||||||
model_id: str,
|
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):
|
class UpdateModelRequest(BaseModel):
|
||||||
|
"""更新模型请求(保留兼容,实际更新使用 ModelUpdateRequest)"""
|
||||||
name: Optional[str] = None
|
name: Optional[str] = None
|
||||||
api_key: Optional[str] = None
|
api_key: Optional[str] = None
|
||||||
endpoint: Optional[str] = None
|
endpoint: Optional[str] = None
|
||||||
@@ -1183,6 +1190,3 @@ class UpdateModelRequest(BaseModel):
|
|||||||
price_per_million_tokens: Optional[float] = None
|
price_per_million_tokens: Optional[float] = None
|
||||||
is_enabled: Optional[bool] = None
|
is_enabled: Optional[bool] = None
|
||||||
|
|
||||||
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
Reference in new issue
Block a user