From 68f798fb2a8c20f2e74ace8770ea883c21a1b0cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A0=95=EC=A7=80=EB=AF=BC?= <108014449+stopmin@users.noreply.github.com> Date: Sat, 20 Jul 2024 00:50:41 +0900 Subject: [PATCH] =?UTF-8?q?usertype=20=EA=B4=80=EB=A0=A8=20API=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20(#131)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/router/user_type_router.py | 92 +++++++++++------------- app/service/user_type_service.py | 116 +++++++++++++++++++------------ 2 files changed, 109 insertions(+), 99 deletions(-) diff --git a/app/router/user_type_router.py b/app/router/user_type_router.py index a7e55a7..8dcafaf 100644 --- a/app/router/user_type_router.py +++ b/app/router/user_type_router.py @@ -1,20 +1,18 @@ -from typing import List, Dict +from typing import Dict, List from fastapi import APIRouter, Depends from groq import BaseModel from sqlalchemy.ext.asyncio import AsyncSession -from app.database.repository import model_to_dict from app.database.session import get_db_session -from app.model.user_type import UserType -from app.recommend.recommend_service import RecommendService, user_id_to_classification_id, \ - user_type_to_classification_id +from app.recommend.recommend_service import user_type_to_classification_id from app.repository.crawled_article_crud import CrawledArticleRepository from app.repository.recommend_crud import RecommendRepository from app.service.user_type_service import ( UserTypeQuestionnaire, UserTypeQuestionnaireRequestDTO, - UserTypeService, calculate_user_type, + UserTypeService, + calculate_user_type, ) from app.utils.generic_response import GenericResponseDTO @@ -27,73 +25,61 @@ class ArticleResponseDTO(BaseModel): content: str pubDate: str image: str + + class UserTypeResponseDTO(BaseModel): userType: Dict recommendNews: List[ArticleResponseDTO] - @user_type_router.get( - "/user-type/questionnaire", + "/usertype/form", response_model=GenericResponseDTO[List[UserTypeQuestionnaire]], ) async def get_questionnaire(): data = await UserTypeService().get_questionnaire() return GenericResponseDTO[List[UserTypeQuestionnaire]]( - data=data, message="Questionnaire retrieved successfully", result=True + data=data, message="유형검사 질문지 조회에 성공", result=True ) -@user_type_router.post("/user-type", response_model=GenericResponseDTO[UserTypeResponseDTO]) +@user_type_router.post( + "/usertype/calculate", response_model=GenericResponseDTO[UserTypeResponseDTO] +) async def create_user_type_by_answers( request: UserTypeQuestionnaireRequestDTO, session: AsyncSession = Depends(get_db_session), ): - recommendNew_ids = [] - if request.id == None: - userType = calculate_user_type( - request, UserTypeService().get_questionnaire_data() - ) - recommendNew_ids = await RecommendRepository().get( - pk=await user_type_to_classification_id(userType), - session=session) - recommendNew_ids = recommendNew_ids.recommend_article_ids - else : - userType = await UserTypeService().create_user_type(request, session) - recommendNew_ids = await RecommendRepository().get( - pk=await user_id_to_classification_id(user_id=userType.user_id, session=session), - session=session) - recommendNew_ids = recommendNew_ids.recommend_article_ids + userType = calculate_user_type(request, UserTypeService().get_questionnaire_data()) + recommendNew_ids = await RecommendRepository().get( + pk=await user_type_to_classification_id(userType), session=session + ) + recommendNew_ids = recommendNew_ids.recommend_article_ids recommendNews = [] for id in recommendNew_ids: temp_article = await CrawledArticleRepository().get(pk=id, session=session) - recommendNews.append(ArticleResponseDTO( - id=id, - title=temp_article.simple_title, - content=temp_article.simple_content, - pubDate=temp_article.published_at.strftime("%Y-%m-%d"), - image=temp_article.image_url - )) - if request.id == None: - return GenericResponseDTO[UserTypeResponseDTO]( - data=UserTypeResponseDTO( - userType={'ISSUE_FINDER': userType[0], - 'LIFESTYLE_CONSUMER': userType[1], - 'ENTERTAINER': userType[2], - 'TECH_SPECIALIST': userType[3], - 'PROFESSIONALS': userType[4]}, - recommendNews=recommendNews - ), message="user type created successfully", result=True - ) - else: - return GenericResponseDTO[UserTypeResponseDTO]( - data=UserTypeResponseDTO( - userType={'ISSUE_FINDER': userType.user_type_issue_finder, - 'LIFESTYLE_CONSUMER': userType.user_type_lifestyle_consumer, - 'ENTERTAINER': userType.user_type_entertainer, - 'TECH_SPECIALIST': userType.user_type_tech_specialist, - 'PROFESSIONALS': userType.user_type_professionals}, - recommendNews=recommendNews - ), message="user type created successfully", result=True + recommendNews.append( + ArticleResponseDTO( + id=id, + title=temp_article.simple_title, + content=temp_article.simple_content, + pubDate=temp_article.published_at.strftime("%Y-%m-%d"), + image=temp_article.image_url, + ) ) + + return GenericResponseDTO[UserTypeResponseDTO]( + data=UserTypeResponseDTO( + userType={ + "ISSUE_FINDER": userType[0], + "LIFESTYLE_CONSUMER": userType[1], + "ENTERTAINER": userType[2], + "TECH_SPECIALIST": userType[3], + "PROFESSIONALS": userType[4], + }, + recommendNews=recommendNews, + ), + message="유형검사 결과가 성공", + result=True, + ) diff --git a/app/service/user_type_service.py b/app/service/user_type_service.py index caf73fa..8b7a032 100644 --- a/app/service/user_type_service.py +++ b/app/service/user_type_service.py @@ -1,5 +1,6 @@ -from typing import List, Optional +from typing import List +from fastapi import HTTPException from groq import BaseModel from sqlalchemy.ext.asyncio import AsyncSession @@ -8,7 +9,6 @@ class UserTypeQuestionnaireRequestDTO(BaseModel): - id: Optional[int] answers: List[int] @@ -53,14 +53,31 @@ def set_user_type_questionnaire(questionnaire_data) -> List[UserTypeQuestionnair def calculate_user_type(answers: UserTypeQuestionnaireRequestDTO, questionnaire_data): user_type = [0 for _ in range(5)] + for i in range(10): # answer in answers.answers: - answer_index = int(answers.answers[i]) # answers의 각 항목을 정수로 변환 - user_type_index = int( - questionnaire_data[i][answer_index + 1][2] - ) # 정수 인덱스로 접근 - if user_type_index == UserTypes.NONE: - continue - user_type[user_type_index] += questionnaire_data[i][answer_index + 1][1] + try: + answer_index = int(answers.answers[i]) # answers의 각 항목을 정수로 변환 + + # 인덱스 범위 확인 + if i >= len(questionnaire_data): + raise HTTPException( + detail="10개의 응답을 입력해주세요.", status_code=400 + ) + if answer_index + 1 >= len(questionnaire_data[i]): + raise HTTPException(detail="0부터 2까지 유효합니다.", status_code=400) + + user_type_index = int( + questionnaire_data[i][answer_index + 1][2] + ) # 정수 인덱스로 접근 + + if user_type_index == UserTypes.NONE: + continue + + user_type[user_type_index] += questionnaire_data[i][answer_index + 1][1] + + except IndexError as e: + raise HTTPException(status_code=500, detail=f"인덱스 오류: {e}") from e + return user_type @@ -69,65 +86,70 @@ def __init__(self): self.questionnaire_data = [ [ "최신 경제 이슈에 대해 얼마나 잘 알고 있습니까?", - ["매우 잘 알고 있다.", 10, UserTypes.ISSUE_FINDER.value['id']], - ["다소 알고 있다.", 5, UserTypes.ISSUE_FINDER.value['id']], - ["잘 모른다.", 0, UserTypes.NONE.value['id']], + ["매우 잘 알고 있다.", 10, UserTypes.ISSUE_FINDER.value["id"]], + ["다소 알고 있다.", 5, UserTypes.ISSUE_FINDER.value["id"]], + ["잘 모른다.", 0, UserTypes.NONE.value["id"]], ], [ "경제 뉴스를 얼마나 자주 찾아보십니까?", - ["매일 확인한다.", 10, UserTypes.ISSUE_FINDER.value['id']], - ["주간 단위로 확인한다.", 5, UserTypes.ISSUE_FINDER.value['id']], - ["가끔 확인한다.", 0, UserTypes.NONE.value['id']], + ["매일 확인한다.", 10, UserTypes.ISSUE_FINDER.value["id"]], + ["주간 단위로 확인한다.", 5, UserTypes.ISSUE_FINDER.value["id"]], + ["가끔 확인한다.", 0, UserTypes.NONE.value["id"]], ], [ "경제 관련 논란이나 논쟁에 얼마나 관심이 있습니까?", - ["매우 관심이 있다.", 10, UserTypes.ISSUE_FINDER.value['id']], - ["다소 관심이 있다.", 5, UserTypes.ISSUE_FINDER.value['id']], - ["잘 모른다.", 0, UserTypes.NONE.value['id']], + ["매우 관심이 있다.", 10, UserTypes.ISSUE_FINDER.value["id"]], + ["다소 관심이 있다.", 5, UserTypes.ISSUE_FINDER.value["id"]], + ["잘 모른다.", 0, UserTypes.NONE.value["id"]], ], [ "경제 정보를 어떻게 활용하시나요?", - ["일상 생활에 적용해본다.", 10, UserTypes.LIFESTYLE_CONSUMER.value['id']], - ["흥미로운 정보는 기억한다.", 10, UserTypes.ENTERTAINER.value['id']], - ["크게 활용하지 않는다.", 0, UserTypes.NONE.value['id']], + [ + "일상 생활에 적용해본다.", + 10, + UserTypes.LIFESTYLE_CONSUMER.value["id"], + ], + ["흥미로운 정보는 기억한다.", 10, UserTypes.ENTERTAINER.value["id"]], + ["크게 활용하지 않는다.", 0, UserTypes.NONE.value["id"]], ], [ "절약이나 소비자 팁에 관심이 있으신가요?", - ["매우 관심이 있다.", 10, UserTypes.LIFESTYLE_CONSUMER.value['id']], - ["다소 관심이 있다.", 5, UserTypes.LIFESTYLE_CONSUMER.value['id']], - ["별로 관심이 없다.", 0, UserTypes.NONE.value['id']], + ["매우 관심이 있다.", 10, UserTypes.LIFESTYLE_CONSUMER.value["id"]], + ["다소 관심이 있다.", 5, UserTypes.LIFESTYLE_CONSUMER.value["id"]], + ["별로 관심이 없다.", 0, UserTypes.NONE.value["id"]], ], [ "경제 관련 이야기를 어떻게 즐기시나요?", - ["심도 깊게 분석한다.", 10, UserTypes.PROFESSIONALS.value['id']], - ["가벼운 마음으로 즐긴다.", 5, UserTypes.ENTERTAINER.value['id']], - ["별로 관심이 없다.", 0, UserTypes.NONE.value['id']], + ["심도 깊게 분석한다.", 10, UserTypes.PROFESSIONALS.value["id"]], + ["가벼운 마음으로 즐긴다.", 5, UserTypes.ENTERTAINER.value["id"]], + ["별로 관심이 없다.", 0, UserTypes.NONE.value["id"]], ], [ "기술과 경제의 결합에 대해 얼마나 잘 이해하고 있습니까?", - ["매우 잘 이해한다.", 10, UserTypes.TECH_SPECIALIST.value['id']], - ["다소 이해한다.", 5, UserTypes.TECH_SPECIALIST.value['id']], - ["잘 모른다.", 0, UserTypes.NONE.value['id']], + ["매우 잘 이해한다.", 10, UserTypes.TECH_SPECIALIST.value["id"]], + ["다소 이해한다.", 5, UserTypes.TECH_SPECIALIST.value["id"]], + ["잘 모른다.", 0, UserTypes.NONE.value["id"]], ], [ "기술 발전이 경제에 미치는 영향에 대해 얼마나 알고 있습니까?", - ["깊이 있는 지식이 있다. ", 10, UserTypes.TECH_SPECIALIST.value['id']], - ["일반적인 이해만 한다. ", 5, UserTypes.TECH_SPECIALIST.value['id']], - ["잘 모른다.", 0, UserTypes.NONE.value['id']], + ["깊이 있는 지식이 있다. ", 10, UserTypes.TECH_SPECIALIST.value["id"]], + ["일반적인 이해만 한다. ", 5, UserTypes.TECH_SPECIALIST.value["id"]], + ["잘 모른다.", 0, UserTypes.NONE.value["id"]], ], [ "전문가 의견이나 통계 데이터에 관심이 있으신가요?", - ["매우 관심이 있다.", 10, UserTypes.PROFESSIONALS.value['id']], - ["다소 관심이 있다.", 5, UserTypes.PROFESSIONALS.value['id']], - ["별로 관심이 없다. ", 5, UserTypes.ENTERTAINER.value['id']], + ["매우 관심이 있다.", 10, UserTypes.PROFESSIONALS.value["id"]], + ["다소 관심이 있다.", 5, UserTypes.PROFESSIONALS.value["id"]], + ["별로 관심이 없다. ", 5, UserTypes.ENTERTAINER.value["id"]], ], [ "경제 분석을 얼마나 자주 읽거나 들으시나요?", - ["자주 읽거나 듣는다.", 10, UserTypes.PROFESSIONALS.value['id']], - ["가끔 읽거나 듣는다.", 5, UserTypes.PROFESSIONALS.value['id']], - ["별로 읽거나 듣지 않는다.", 5, UserTypes.ENTERTAINER.value['id']], + ["자주 읽거나 듣는다.", 10, UserTypes.PROFESSIONALS.value["id"]], + ["가끔 읽거나 듣는다.", 5, UserTypes.PROFESSIONALS.value["id"]], + ["별로 읽거나 듣지 않는다.", 5, UserTypes.ENTERTAINER.value["id"]], ], ] + def get_questionnaire_data(self): return self.questionnaire_data @@ -148,19 +170,21 @@ async def create_user_type( if col == max_user_type: user_type_id = idx for user_type in UserTypes: - if user_type.value['id'] == user_type_id: + if user_type.value["id"] == user_type_id: user_type_enum = user_type return await UserTypeRepository().create( user_type=UserType( user_id=answers.id, - user_type_issue_finder=user_types[UserTypes.ISSUE_FINDER.value['id']], + user_type_issue_finder=user_types[UserTypes.ISSUE_FINDER.value["id"]], user_type_lifestyle_consumer=user_types[ - UserTypes.LIFESTYLE_CONSUMER.value['id'] + UserTypes.LIFESTYLE_CONSUMER.value["id"] + ], + user_type_entertainer=user_types[UserTypes.ENTERTAINER.value["id"]], + user_type_tech_specialist=user_types[ + UserTypes.TECH_SPECIALIST.value["id"] ], - user_type_entertainer=user_types[UserTypes.ENTERTAINER.value['id']], - user_type_tech_specialist=user_types[UserTypes.TECH_SPECIALIST.value['id']], - user_type_professionals=user_types[UserTypes.PROFESSIONALS.value['id']], - user_type=user_type_enum.value['name'] + user_type_professionals=user_types[UserTypes.PROFESSIONALS.value["id"]], + user_type=user_type_enum.value["name"], ), session=session, )