diff --git a/app/api/api_router.py b/app/api/api_router.py index f1c7c0f..45e22f4 100644 --- a/app/api/api_router.py +++ b/app/api/api_router.py @@ -2,7 +2,16 @@ from fastapi import APIRouter -from app.api import annotation_api, api_key_api, chat_tab_api, driver_api, query_api, test_api, user_db_api +from app.api import ( + annotation_api, + api_key_api, + chat_tab_api, + driver_api, + query_api, + test_api, + user_db_api, + chat_messages_api, +) api_router = APIRouter() @@ -13,6 +22,7 @@ api_router.include_router(driver_api.router, prefix="/driver", tags=["Driver"]) api_router.include_router(user_db_api.router, prefix="/user/db", tags=["UserDb"]) api_router.include_router(api_key_api.router, prefix="/keys", tags=["API Key"]) -api_router.include_router(chat_tab_api.router, prefix="/chats", tags=["AI Chat"]) +api_router.include_router(chat_tab_api.router, prefix="/chatTabs", tags=["Chat Tab"]) api_router.include_router(annotation_api.router, prefix="/annotations", tags=["Annotation"]) api_router.include_router(query_api.router, prefix="/query", tags=["query"]) +api_router.include_router(chat_messages_api.router, prefix="/chatMessages", tags=["Chat Message"]) diff --git a/app/api/chat_messages_api.py b/app/api/chat_messages_api.py new file mode 100644 index 0000000..d63ca92 --- /dev/null +++ b/app/api/chat_messages_api.py @@ -0,0 +1,39 @@ +from fastapi import APIRouter, Depends + +from app.core.enum.sender import SenderEnum +from app.core.response import ResponseMessage +from app.core.status import CommonCode +from app.schemas.chat_message.request_model import ChatMessagesReqeust +from app.schemas.chat_message.response_model import ChatMessagesResponse +from app.services.chat_message_service import ChatMessageService, chat_message_service + +chat_message_service_dependency = Depends(lambda: chat_message_service) + +router = APIRouter() + + +@router.post( + "/create", + response_model=ResponseMessage[ChatMessagesResponse], + summary="새로운 사용자 질의 생성", +) +async def create_chat_message( + request: ChatMessagesReqeust, service: ChatMessageService = chat_message_service_dependency +) -> ResponseMessage[ChatMessagesResponse]: + """ + `tabId`, `message`를 받아 DB에 저장하고 AI를 통해 사용자 질의를 분석하고 답변을 생성하여 반환합니다. + """ + new_messages = await service.create_chat_message(request) + + print(ChatMessagesResponse.model_json_schema()) + + response_data = ChatMessagesResponse( + id=new_messages.id, + chat_tab_id=new_messages.chat_tab_id, + sender=SenderEnum(new_messages.sender), + message=new_messages.message, + created_at=new_messages.created_at, + updated_at=new_messages.updated_at, + ) + + return ResponseMessage.success(value=response_data, code=CommonCode.SUCCESS_CREATE_CHAT_MESSAGES) diff --git a/app/api/chat_tab_api.py b/app/api/chat_tab_api.py index a29af95..de08f37 100644 --- a/app/api/chat_tab_api.py +++ b/app/api/chat_tab_api.py @@ -18,13 +18,13 @@ summary="새로운 Chat Tab 생성", description="새로운 Chat Tab을 생성하여 로컬 데이터베이스에 저장합니다.", ) -def store_chat_tab( +def create_chat_tab( chatName: ChatTabBase, service: ChatTabService = chat_tab_service_dependency ) -> ResponseMessage[ChatTabResponse]: """ - **name**: 새로운 Chat_tab 이름 (예: "채팅 타이틀") """ - created_chat_tab = service.store_chat_tab(chatName) + created_chat_tab = service.create_chat_tab(chatName) response_data = ChatTabResponse( id=created_chat_tab.id, diff --git a/app/api/query_api.py b/app/api/query_api.py index 9504a24..f924591 100644 --- a/app/api/query_api.py +++ b/app/api/query_api.py @@ -27,7 +27,6 @@ def execution( service: QueryService = query_service_dependency, userDbservice: UserDbService = user_db_service_dependency, ) -> ResponseMessage[dict | str | None]: - db_info = userDbservice.find_profile(query_info.user_db_id) result = service.execution(query_info, db_info) @@ -46,7 +45,6 @@ def execution_test( service: QueryService = query_service_dependency, userDbservice: UserDbService = user_db_service_dependency, ) -> ResponseMessage[Any]: - db_info = userDbservice.find_profile(query_info.user_db_id) result = service.execution_test(query_info, db_info) @@ -62,7 +60,6 @@ def find_query_history( chat_tab_id: str, service: QueryService = query_service_dependency, ) -> ResponseMessage[dict]: - result = service.find_query_history(chat_tab_id) if not result.is_successful: diff --git a/app/api/user_db_api.py b/app/api/user_db_api.py index ffd6656..f837dc3 100644 --- a/app/api/user_db_api.py +++ b/app/api/user_db_api.py @@ -90,7 +90,6 @@ def delete_profile( def find_all_profile( service: UserDbService = user_db_service_dependency, ) -> ResponseMessage[list[DBProfile]]: - result = service.find_all_profile() if not result.is_successful: @@ -104,7 +103,6 @@ def find_all_profile( summary="특정 DB의 전체 스키마 조회", ) def find_schemas(profile_id: str, service: UserDbService = user_db_service_dependency) -> ResponseMessage[list[str]]: - db_info = service.find_profile(profile_id) result = service.find_schemas(db_info) @@ -121,7 +119,6 @@ def find_schemas(profile_id: str, service: UserDbService = user_db_service_depen def find_tables( profile_id: str, schema_name: str, service: UserDbService = user_db_service_dependency ) -> ResponseMessage[list[str]]: - db_info = service.find_profile(profile_id) result = service.find_tables(db_info, schema_name) @@ -138,7 +135,6 @@ def find_tables( def find_columns( profile_id: str, schema_name: str, table_name: str, service: UserDbService = user_db_service_dependency ) -> ResponseMessage[list[ColumnInfo]]: - db_info = service.find_profile(profile_id) result = service.find_columns(db_info, schema_name, table_name) @@ -156,7 +152,6 @@ def find_columns( def find_all_schema_info( profile_id: str, service: UserDbService = user_db_service_dependency ) -> ResponseMessage[list[TableInfo]]: - db_info = service.find_profile(profile_id) full_schema_info = service.get_full_schema_info(db_info) diff --git a/app/core/enum/db_key_prefix_name.py b/app/core/enum/db_key_prefix_name.py index 819edee..252a801 100644 --- a/app/core/enum/db_key_prefix_name.py +++ b/app/core/enum/db_key_prefix_name.py @@ -8,8 +8,9 @@ class DBSaveIdEnum(Enum): user_db = "USER-DB" driver = "DRIVER" api_key = "API-KEY" - chat_tab = "CHAT_TAB" + chat_tab = "CHAT-TAB" query = "QUERY" + chat_message = "CHAT-MESSAGE" database_annotation = "DB-ANNO" table_annotation = "TBL-ANNO" diff --git a/app/core/enum/sender.py b/app/core/enum/sender.py new file mode 100644 index 0000000..a6394b2 --- /dev/null +++ b/app/core/enum/sender.py @@ -0,0 +1,8 @@ +from enum import Enum + + +class SenderEnum(str, Enum): + """채팅 메시지 발신자 구분""" + + user = "U" + ai = "A" diff --git a/app/core/status.py b/app/core/status.py index 86e73d9..130614f 100644 --- a/app/core/status.py +++ b/app/core/status.py @@ -33,7 +33,7 @@ class CommonCode(Enum): SUCCESS_UPDATE_API_KEY = (status.HTTP_200_OK, "2201", "API KEY가 성공적으로 수정되었습니다.") SUCCESS_GET_API_KEY = (status.HTTP_200_OK, "2202", "API KEY 정보를 성공적으로 조회했습니다.") - """ AI CHAT, DB 성공 코드 - 23xx """ + """ CHAT TAB 성공 코드 - 23xx """ SUCCESS_CHAT_TAB_CREATE = (status.HTTP_200_OK, "2300", "새로운 채팅 탭이 성공적으로 생성하였습니다.") SUCCESS_CHAT_TAB_UPDATE = (status.HTTP_200_OK, "2301", "채팅 탭 이름이 성공적으로 수정되었습니다.") SUCCESS_CHAT_TAB_DELETE = (status.HTTP_200_OK, "2302", "채팅 탭을 성공적으로 삭제되었습니다.") @@ -50,6 +50,9 @@ class CommonCode(Enum): SUCCESS_FIND_QUERY_HISTORY = (status.HTTP_200_OK, "2102", "쿼리 이력 조회를 성공하였습니다.") SUCCESS_EXECUTION_TEST = (status.HTTP_201_CREATED, "2400", "쿼리 TEST를 성공적으로 수행하였습니다.") + """ ChAT MESSAGE 성공 코드 - 26xx """ + SUCCESS_CREATE_CHAT_MESSAGES = (status.HTTP_201_CREATED, "2600", "메시지를 성공적으로 요청하였습니다.") + # ======================================= # 클라이언트 에러 (Client Error) - 4xxx # ======================================= @@ -96,6 +99,9 @@ class CommonCode(Enum): NO_CHAT_KEY = (status.HTTP_400_BAD_REQUEST, "4501", "CHAT 키는 필수 값입니다.") NO_QUERY = (status.HTTP_400_BAD_REQUEST, "4500", "쿼리는 필수 값입니다.") + """ CHAT MESSAGE 에러 코드 - 46xx """ + INVALID_CHAT_MESSAGE_REQUEST = (status.HTTP_400_BAD_REQUEST, "4600", "AI 채팅 요청 데이터가 유효하지 않습니다.") + # ================================== # 서버 에러 (Server Error) - 5xx # ================================== @@ -144,8 +150,11 @@ class CommonCode(Enum): ) """ SQL 서버 에러 코드 - 55xx """ + FAIL_CREATE_QUERY = (status.HTTP_500_INTERNAL_SERVER_ERROR, "5170", "쿼리 실행 정보 저장 중 에러가 발생했습니다.") + """ CHAT MESSAGE 에러 코드 - 56xx """ + def __init__(self, http_status: int, code: str, message: str): """Enum 멤버가 생성될 때 각 값을 속성으로 할당합니다.""" self.http_status = http_status diff --git a/app/repository/chat_message_repository.py b/app/repository/chat_message_repository.py index 6e1c67f..4539b0c 100644 --- a/app/repository/chat_message_repository.py +++ b/app/repository/chat_message_repository.py @@ -1,10 +1,48 @@ import sqlite3 from app.core.utils import get_db_path -from app.schemas.chat_tab.db_model import ChatMessageInDB +from app.schemas.chat_message.db_model import ChatMessageInDB class ChatMessageRepository: + def create_chat_message(self, new_id: str, sender: str, chat_tab_id: str, message: str) -> ChatMessageInDB: + """ + 새로운 채팅을 데이터베이스에 저장하고, 저장된 객체를 반환합니다. + """ + + db_path = get_db_path() + conn = None + try: + conn = sqlite3.connect(str(db_path), timeout=10) + conn.row_factory = sqlite3.Row + cursor = conn.cursor() + + cursor.execute( + """ + INSERT INTO chat_message (id, chat_tab_id, sender, message) + VALUES (?, ?, ?, ?) + """, + ( + new_id, + chat_tab_id, + sender, + message, + ), + ) + conn.commit() + + cursor.execute("SELECT * FROM chat_message WHERE id = ?", (new_id,)) + created_row = cursor.fetchone() + + if not created_row: + return None + + return ChatMessageInDB.model_validate(dict(created_row)) + + finally: + if conn: + conn.close() + def get_chat_messages_by_tabId(self, id: str) -> list[ChatMessageInDB]: """주어진 chat_tab_id에 해당하는 모든 메시지를 가져옵니다.""" db_path = get_db_path() diff --git a/app/schemas/chat_message/base_model.py b/app/schemas/chat_message/base_model.py new file mode 100644 index 0000000..049770c --- /dev/null +++ b/app/schemas/chat_message/base_model.py @@ -0,0 +1,24 @@ +from datetime import datetime + +from pydantic import BaseModel, Field + +from app.core.enum.db_key_prefix_name import DBSaveIdEnum +from app.core.exceptions import APIException +from app.core.status import CommonCode + + +class ChatMessagesBase(BaseModel): + id: str = Field(..., description="고유 ID") + created_at: datetime = Field(..., description="생성 시각") + updated_at: datetime = Field(..., description="마지막 수정 시각") + + +class RequestBase(BaseModel): + """요청 스키마의 기본 모델""" + + def validate_chat_tab_id(self) -> None: + """채팅 탭 ID에 대한 유효성 검증 로직을 수행합니다.""" + + required_prefix = DBSaveIdEnum.chat_tab.value + "-" + if not self.chat_tab_id.startswith(required_prefix): + raise APIException(CommonCode.INVALID_CHAT_TAB_ID_FORMAT) diff --git a/app/schemas/chat_message/db_model.py b/app/schemas/chat_message/db_model.py new file mode 100644 index 0000000..2833efd --- /dev/null +++ b/app/schemas/chat_message/db_model.py @@ -0,0 +1,13 @@ +from pydantic import Field + +from app.core.enum.sender import SenderEnum +from app.schemas.chat_message.base_model import ChatMessagesBase + + +class ChatMessageInDB(ChatMessagesBase): + chat_tab_id: str = Field(..., description="해당 메시지가 속한 채팅 탭의 ID") + sender: SenderEnum = Field(..., description="메시지 발신자 ('A' 또는 'U')") + message: str = Field(..., description="메시지 내용") + + class Config: + use_enum_values = True diff --git a/app/schemas/chat_message/request_model.py b/app/schemas/chat_message/request_model.py new file mode 100644 index 0000000..fef913a --- /dev/null +++ b/app/schemas/chat_message/request_model.py @@ -0,0 +1,13 @@ +from pydantic import Field + +from app.schemas.chat_message.base_model import RequestBase + + +class ChatMessagesReqeust(RequestBase): + """채팅 메시지 생성 요청 스키마""" + + chat_tab_id: str = Field(..., description="채팅 탭의 고유 ID") + message: str = Field(..., description="메시지 내용") + + def validate(self): + self.validate_chat_tab_id() diff --git a/app/schemas/chat_message/response_model.py b/app/schemas/chat_message/response_model.py new file mode 100644 index 0000000..f1ce682 --- /dev/null +++ b/app/schemas/chat_message/response_model.py @@ -0,0 +1,13 @@ +from pydantic import Field + +from app.core.enum.sender import SenderEnum +from app.schemas.chat_message.base_model import ChatMessagesBase + + +class ChatMessagesResponse(ChatMessagesBase): + chat_tab_id: str = Field(..., description="해당 메시지가 속한 채팅 탭의 ID") + sender: SenderEnum = Field(..., description="메시지 발신자 ('AI' 또는 'User')") + message: str = Field(..., description="메시지 내용") + + class Config: + use_enum_values = True diff --git a/app/schemas/chat_tab/base_model.py b/app/schemas/chat_tab/base_model.py index 9c4e9c8..f642c19 100644 --- a/app/schemas/chat_tab/base_model.py +++ b/app/schemas/chat_tab/base_model.py @@ -2,6 +2,7 @@ from pydantic import BaseModel, Field +from app.core.enum.db_key_prefix_name import DBSaveIdEnum from app.core.exceptions import APIException from app.core.status import CommonCode @@ -35,3 +36,11 @@ def validate_chat_tab_name(self) -> None: # 특정 특수문자를 검사하는 예시 if re.search(r"[;\"'`<>]", self.name): raise APIException(CommonCode.INVALID_CHAT_TAB_NAME_CONTENT) + + def validate_chat_tab_id(self) -> None: + """채팅 탭 ID에 대한 유효성 검증 로직을 수행합니다.""" + + # 1. 'CHAT-TAB-' 접두사 검증 + required_prefix = DBSaveIdEnum.chat_tab.value + "-" + if not self.id.startswith(required_prefix): + raise APIException(CommonCode.INVALID_CHAT_TAB_ID_FORMAT) diff --git a/app/schemas/chat_tab/db_model.py b/app/schemas/chat_tab/db_model.py index ddd37fd..d548797 100644 --- a/app/schemas/chat_tab/db_model.py +++ b/app/schemas/chat_tab/db_model.py @@ -13,9 +13,6 @@ class ChatTabInDB(ChatTabBase): created_at: datetime updated_at: datetime - class Config: - from_attributes = True - class ChatMessageInDB(ChatTabBase): """데이터베이스에 저장된 형태의 메시지 스키마 (내부용)""" @@ -26,6 +23,3 @@ class ChatMessageInDB(ChatTabBase): message: str = Field(..., description="메시지 내용") created_at: datetime updated_at: datetime - - class Config: - from_attributes = True diff --git a/app/schemas/chat_tab/update_model.py b/app/schemas/chat_tab/update_model.py index e9ca291..c42c56b 100644 --- a/app/schemas/chat_tab/update_model.py +++ b/app/schemas/chat_tab/update_model.py @@ -7,3 +7,6 @@ class ChatTabUpdate(ChatTabBase): """채팅 탭 이름 수정을 위한 스키마""" name: str = Field(None, description="수정할 채팅 탭 이름") + + def validate(self): + self.validate_chat_tab_name(["name"]) diff --git a/app/schemas/chat_tab/validation_utils.py b/app/schemas/chat_tab/validation_utils.py deleted file mode 100644 index 82470df..0000000 --- a/app/schemas/chat_tab/validation_utils.py +++ /dev/null @@ -1,13 +0,0 @@ -from app.core.enum.db_key_prefix_name import DBSaveIdEnum -from app.core.exceptions import APIException -from app.core.status import CommonCode - - -# 리팩토링 예정 -def validate_chat_tab_id(id: str | None) -> None: - """채팅 탭 ID에 대한 유효성 검증 로직을 수행합니다.""" - - # 1. 'CHAT-TAB-' 접두사 검증 - required_prefix = DBSaveIdEnum.chat_tab.value + "-" - if not id.startswith(required_prefix): - raise APIException(CommonCode.INVALID_CHAT_TAB_ID_FORMAT) diff --git a/app/services/chat_message_service.py b/app/services/chat_message_service.py new file mode 100644 index 0000000..493554c --- /dev/null +++ b/app/services/chat_message_service.py @@ -0,0 +1,146 @@ +import os +import sqlite3 + +import httpx +from fastapi import Depends + +from app.core.enum.db_key_prefix_name import DBSaveIdEnum +from app.core.enum.sender import SenderEnum +from app.core.exceptions import APIException +from app.core.status import CommonCode +from app.core.utils import generate_prefixed_uuid +from app.repository.chat_message_repository import ChatMessageRepository, chat_message_repository +from app.schemas.chat_message.db_model import ChatMessageInDB +from app.schemas.chat_message.request_model import ChatMessagesReqeust +from app.schemas.chat_message.response_model import ChatMessagesResponse + +chat_message_repository_dependency = Depends(lambda: chat_message_repository) + +AI_SERVER_URL = os.getenv("ENV_AI_SERVER_URL") + + +class ChatMessageService: + def __init__(self, repository: ChatMessageRepository = chat_message_repository): + self.repository = repository + + def get_chat_messages_by_tabId(self, tabId: str) -> ChatMessageInDB: + """ + 채팅 탭 메타데이터와 메시지 목록을 모두 가져와서 조합합니다. + 탭이 존재하지 않으면 예외를 발생시킵니다. + """ + try: + return self.repository.get_chat_messages_by_tabId(tabId) + + except sqlite3.Error as e: + raise APIException(CommonCode.FAIL) from e + + async def create_chat_message(self, request: ChatMessagesReqeust) -> ChatMessagesResponse: + # 1. tab_id 확인 + chat_tab_id = request.chat_tab_id + + # chat_tab_id 유효성 검사 + try: + request.validate() + except ValueError as e: + raise APIException(CommonCode.INVALID_CHAT_MESSAGE_REQUEST, detail=str(e)) from e + + try: + # 같은 서비스 메서드 호출 + self.get_chat_messages_by_tabId(chat_tab_id) + except sqlite3.Error as e: + raise APIException(CommonCode.FAIL) from e + + # 2. 사용자 질의 저장 + try: + user_request = self._transform_user_request_to_db_models(request) + except sqlite3.Error as e: + raise APIException(CommonCode.FAIL) from e + + # 3. AI 서버에 요청 + ai_response = await self._request_chat_message_to_ai_server(user_request) + + # 4. AI 서버 응답 저장 + response = self._transform_ai_response_to_db_models(request, ai_response) + + return response + + def _transform_user_request_to_db_models(self, request: ChatMessagesReqeust) -> ChatMessageInDB: + """사용자 질의를 데이터베이스에 저장합니다.""" + + new_id = generate_prefixed_uuid(DBSaveIdEnum.chat_message.value) + sender = SenderEnum.user + + chat_tab_id = request.chat_tab_id + message = request.message + + try: + created_row = self.repository.create_chat_message( + new_id=new_id, + sender=sender, + chat_tab_id=chat_tab_id, + message=message, + ) + if not created_row: + raise APIException(CommonCode.FAIL_TO_VERIFY_CREATION) + + return created_row + + except sqlite3.Error as e: + if "database is locked" in str(e): + raise APIException(CommonCode.DB_BUSY) from e + raise APIException(CommonCode.FAIL) from e + + async def _request_chat_message_to_ai_server(self, user_request: ChatMessagesReqeust) -> dict: + """AI 서버에 사용자 질의를 보내고 답변을 받아옵니다.""" + # 1. DB에서 해당 탭의 모든 메시지 조회 + messages: list[ChatMessageInDB] = self.repository.get_chat_messages_by_tabId(user_request.chat_tab_id) + + if not messages: + history = [] + latest_message = user_request.message # DB에 없으면 요청 메시지 그대로 + else: + history = [{"role": m.sender, "content": m.message} for m in messages[:-1]] + latest_message = messages[-1].message + + # 3. AI 서버에 보내는 DATA + request_body = {"question": latest_message, "chat_history": history} + + # 4. AI 서버에 POST 요청 + async with httpx.AsyncClient() as client: + try: + response = await client.post(AI_SERVER_URL, json=request_body, timeout=60.0) + response.raise_for_status() + return response.json() + except httpx.HTTPStatusError as e: + raise APIException(CommonCode.FAIL_AI_SERVER_PROCESSING) from e + except httpx.RequestError as e: + raise APIException(CommonCode.FAIL_AI_SERVER_CONNECTION) from e + + def _transform_ai_response_to_db_models(self, request: ChatMessagesReqeust, ai_response: str) -> ChatMessageInDB: + """AI 서버에서 받은 답변을 데이터베이스에 저장합니다.""" + + new_id = generate_prefixed_uuid(DBSaveIdEnum.chat_message.value) + sender = SenderEnum.ai + + chat_tab_id = request.chat_tab_id + message = ai_response["answer"] + + try: + created_row = self.repository.create_chat_message( + new_id=new_id, + sender=sender, + chat_tab_id=chat_tab_id, + message=message, + ) + if not created_row: + raise APIException(CommonCode.FAIL_TO_VERIFY_CREATION) + + return created_row + + except sqlite3.Error as e: + if "database is locked" in str(e): + raise APIException(CommonCode.DB_BUSY) from e + raise APIException(CommonCode.FAIL) from e + + +chat_message_service = ChatMessageService() diff --git a/app/services/chat_tab_service.py b/app/services/chat_tab_service.py index c7a3f25..f2e63ff 100644 --- a/app/services/chat_tab_service.py +++ b/app/services/chat_tab_service.py @@ -6,34 +6,29 @@ from app.core.exceptions import APIException from app.core.status import CommonCode from app.core.utils import generate_prefixed_uuid -from app.repository.chat_message_repository import ChatMessageRepository, chat_message_repository from app.repository.chat_tab_repository import ChatTabRepository, chat_tab_repository from app.schemas.chat_tab.base_model import ChatTabBase -from app.schemas.chat_tab.db_model import ChatMessageInDB, ChatTabInDB +from app.schemas.chat_tab.db_model import ChatTabInDB from app.schemas.chat_tab.update_model import ChatTabUpdate -from app.schemas.chat_tab.validation_utils import validate_chat_tab_id # 삭제 예정 chat_tab_repository_dependency = Depends(lambda: chat_tab_repository) -chat_tab_repository_dependency = Depends(lambda: chat_tab_repository) class ChatTabService: def __init__( self, - tab_repository: ChatTabRepository = chat_tab_repository, - message_repository: ChatMessageRepository = chat_message_repository, + repository: ChatTabRepository = chat_tab_repository, ): - self.tab_repository = tab_repository - self.message_repository = message_repository + self.repository = repository - def store_chat_tab(self, chatName: ChatTabBase) -> ChatTabInDB: + def create_chat_tab(self, chatName: ChatTabBase) -> ChatTabInDB: """새로운 AI 채팅을 데이터베이스에 저장합니다.""" chatName.validate_chat_tab_name() new_id = generate_prefixed_uuid(DBSaveIdEnum.chat_tab.value) try: - created_row = self.tab_repository.create_chat_tab( + created_row = self.repository.create_chat_tab( new_id=new_id, name=chatName.name, ) @@ -53,7 +48,7 @@ def updated_chat_tab(self, chatID: str, chatName: ChatTabUpdate) -> ChatTabInDB: """TabID에 해당하는 AIChatTab name을 수정합니다.""" chatName.validate_chat_tab_name() try: - updated_chat_tab = self.tab_repository.updated_chat_tab(chatID, chatName.name) + updated_chat_tab = self.repository.updated_chat_tab(chatID, chatName.name) if not updated_chat_tab: raise APIException(CommonCode.NO_CHAT_TAB_DATA) @@ -67,7 +62,7 @@ def updated_chat_tab(self, chatID: str, chatName: ChatTabUpdate) -> ChatTabInDB: def delete_chat_tab(self, tabId: str) -> None: """TabID에 해당하는 AIChatTab을 삭제합니다.""" try: - is_deleted = self.tab_repository.delete_chat_tab(tabId) + is_deleted = self.repository.delete_chat_tab(tabId) if not is_deleted: raise APIException(CommonCode.NO_CHAT_TAB_DATA) except sqlite3.Error as e: @@ -78,17 +73,19 @@ def delete_chat_tab(self, tabId: str) -> None: def get_all_chat_tab(self) -> ChatTabInDB: """데이터베이스에 저장된 모든 Chat_tab을 조회합니다.""" try: - return self.tab_repository.get_all_chat_tab() + return self.repository.get_all_chat_tab() except sqlite3.Error as e: raise APIException(CommonCode.FAIL) from e def get_chat_tab_by_tabId(self, tabId: str) -> ChatTabInDB: """데이터베이스에 저장된 특정 Chat_tab을 조회합니다.""" - # 리팩토링 예정 - validate_chat_tab_id(tabId) + try: + tabId.validate(tabId) + except ValueError as e: + raise APIException(CommonCode.INVALID_ANNOTATION_REQUEST, detail=str(e)) from e try: - chat_tab = self.tab_repository.get_chat_tab_by_id(tabId) + chat_tab = self.repository.get_chat_tab_by_id(tabId) if not chat_tab: raise APIException(CommonCode.NO_CHAT_TAB_DATA) @@ -97,16 +94,5 @@ def get_chat_tab_by_tabId(self, tabId: str) -> ChatTabInDB: except sqlite3.Error as e: raise APIException(CommonCode.FAIL) from e - def get_chat_messages_by_tabId(self, tabId: str) -> ChatMessageInDB: - """ - 채팅 탭 메타데이터와 메시지 목록을 모두 가져와서 조합합니다. - 탭이 존재하지 않으면 예외를 발생시킵니다. - """ - try: - return self.message_repository.get_chat_messages_by_tabId(tabId) - - except sqlite3.Error as e: - raise APIException(CommonCode.FAIL) from e - chat_tab_service = ChatTabService()