From a2ed335e59cd14034947f1ff16959ddaf7faed3f Mon Sep 17 00:00:00 2001 From: lanceyq <1982376970@qq.com> Date: Thu, 5 Mar 2026 18:04:46 +0800 Subject: [PATCH] [add] Repeatability test --- api/app/controllers/ontology_controller.py | 24 ++++++++++++++----- .../controllers/ontology_secondary_routes.py | 21 ++++++++++++---- api/app/models/ontology_class.py | 5 +++- 3 files changed, 39 insertions(+), 11 deletions(-) diff --git a/api/app/controllers/ontology_controller.py b/api/app/controllers/ontology_controller.py index c892b013..3d2a1bdb 100644 --- a/api/app/controllers/ontology_controller.py +++ b/api/app/controllers/ontology_controller.py @@ -25,7 +25,7 @@ from typing import Dict, Optional, List from urllib.parse import quote from fastapi import APIRouter, Depends, HTTPException, File, UploadFile, Form, Header -from fastapi.responses import StreamingResponse +from fastapi.responses import StreamingResponse, JSONResponse from sqlalchemy.orm import Session from app.core.config import settings @@ -289,7 +289,8 @@ async def extract_ontology( async def create_scene( request: SceneCreateRequest, db: Session = Depends(get_db), - current_user: User = Depends(get_current_user) + current_user: User = Depends(get_current_user), + x_language_type: Optional[str] = Header(None, alias="X-Language-Type") ): """创建本体场景 @@ -360,8 +361,18 @@ async def create_scene( return fail(BizCode.BAD_REQUEST, "请求参数无效", str(e)) except RuntimeError as e: - api_logger.error(f"Runtime error in scene creation: {str(e)}", exc_info=True) - return fail(BizCode.INTERNAL_ERROR, "场景创建失败", str(e)) + err_str = str(e) + if "UniqueViolation" in err_str or "uq_workspace_scene_name" in err_str: + api_logger.warning(f"Duplicate scene name '{request.scene_name}' in workspace {current_user.current_workspace_id}") + from app.core.language_utils import get_language_from_header + lang = get_language_from_header(x_language_type) + if lang == "en": + msg = fail(BizCode.BAD_REQUEST, "Scene name already exists", f"A scene named \"{request.scene_name}\" already exists in the current workspace. Please use a different name.") + else: + msg = fail(BizCode.BAD_REQUEST, "场景名称已存在", f"当前工作空间下已存在名为「{request.scene_name}」的场景,请使用其他名称") + return JSONResponse(status_code=400, content=msg) + api_logger.error(f"Runtime error in scene creation: {err_str}", exc_info=True) + return fail(BizCode.INTERNAL_ERROR, "场景创建失败", err_str) except Exception as e: api_logger.error(f"Unexpected error in scene creation: {str(e)}", exc_info=True) @@ -661,7 +672,8 @@ async def get_scenes( async def create_class( request: ClassCreateRequest, db: Session = Depends(get_db), - current_user: User = Depends(get_current_user) + current_user: User = Depends(get_current_user), + x_language_type: Optional[str] = Header(None, alias="X-Language-Type") ): """创建本体类型 @@ -676,7 +688,7 @@ async def create_class( ApiResponse: 包含创建的类型信息 """ from app.controllers.ontology_secondary_routes import create_class_handler - return await create_class_handler(request, db, current_user) + return await create_class_handler(request, db, current_user, x_language_type) @router.put("/class/{class_id}", response_model=ApiResponse) diff --git a/api/app/controllers/ontology_secondary_routes.py b/api/app/controllers/ontology_secondary_routes.py index 607a0739..a0609605 100644 --- a/api/app/controllers/ontology_secondary_routes.py +++ b/api/app/controllers/ontology_secondary_routes.py @@ -7,7 +7,7 @@ from uuid import UUID from typing import Optional -from fastapi import Depends +from fastapi import Depends, Header from sqlalchemy.orm import Session from app.core.error_codes import BizCode @@ -238,7 +238,8 @@ async def scenes_handler( async def create_class_handler( request: ClassCreateRequest, db: Session = Depends(get_db), - current_user: User = Depends(get_current_user) + current_user: User = Depends(get_current_user), + x_language_type: Optional[str] = None ): """创建本体类型(统一使用列表形式,支持单个或批量)""" @@ -334,8 +335,20 @@ async def create_class_handler( return fail(BizCode.BAD_REQUEST, "请求参数无效", str(e)) except RuntimeError as e: - api_logger.error(f"Runtime error in class creation: {str(e)}", exc_info=True) - return fail(BizCode.INTERNAL_ERROR, "类型创建失败", str(e)) + err_str = str(e) + if "UniqueViolation" in err_str or "uq_scene_class_name" in err_str: + api_logger.warning(f"Duplicate class name in scene {request.scene_id}") + from app.core.language_utils import get_language_from_header + from fastapi.responses import JSONResponse + lang = get_language_from_header(x_language_type) + class_name = request.classes[0].class_name if request.classes else "" + if lang == "en": + msg = fail(BizCode.BAD_REQUEST, "Class name already exists", f"A class named \"{class_name}\" already exists in this scene. Please use a different name.") + else: + msg = fail(BizCode.BAD_REQUEST, "类型名称已存在", f"当前场景下已存在名为「{class_name}」的类型,请使用其他名称") + return JSONResponse(status_code=400, content=msg) + api_logger.error(f"Runtime error in class creation: {err_str}", exc_info=True) + return fail(BizCode.INTERNAL_ERROR, "类型创建失败", err_str) except Exception as e: api_logger.error(f"Unexpected error in class creation: {str(e)}", exc_info=True) diff --git a/api/app/models/ontology_class.py b/api/app/models/ontology_class.py index a8468090..eb38d06f 100644 --- a/api/app/models/ontology_class.py +++ b/api/app/models/ontology_class.py @@ -9,7 +9,7 @@ Classes: import datetime import uuid -from sqlalchemy import Column, String, DateTime, Text, ForeignKey, Boolean +from sqlalchemy import Column, String, DateTime, Text, ForeignKey, Boolean, UniqueConstraint from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import relationship from app.db import Base @@ -18,6 +18,9 @@ from app.db import Base class OntologyClass(Base): """本体类型表 - 用于存储某个场景提取出来的本体类型信息""" __tablename__ = "ontology_class" + __table_args__ = ( + UniqueConstraint('scene_id', 'class_name', name='uq_scene_class_name'), + ) # 主键 class_id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4, index=True, comment="类型ID")