From d0e194e58fa6bd65a3a398df7e37aaf8b6af1580 Mon Sep 17 00:00:00 2001 From: yjoonjang Date: Wed, 10 Apr 2024 16:39:16 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=EC=9E=90=EC=86=8C=EC=84=9C=20model?= =?UTF-8?q?=EC=97=90=20question=20=EC=A0=80=EC=9E=A5=EB=90=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=84=A4=EC=A0=95=20=ED=9B=84=20generate=20?= =?UTF-8?q?=EC=8B=9C=20=EC=9E=90=EC=86=8C=EC=84=9C=20=EC=A0=80=EC=9E=A5?= =?UTF-8?q?=EB=90=98=EB=8F=84=EB=A1=9D=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../0003_resume_question_chathistory.py | 42 +++++++++++ .../migrations/0004_alter_resume_due_date.py | 18 +++++ .../migrations/0005_alter_resume_due_date.py | 18 +++++ resume/models.py | 5 +- resume/serializers.py | 1 + resume/utils.py | 2 +- resume/views.py | 73 ++++++++++++------- 7 files changed, 129 insertions(+), 30 deletions(-) create mode 100644 resume/migrations/0003_resume_question_chathistory.py create mode 100644 resume/migrations/0004_alter_resume_due_date.py create mode 100644 resume/migrations/0005_alter_resume_due_date.py diff --git a/resume/migrations/0003_resume_question_chathistory.py b/resume/migrations/0003_resume_question_chathistory.py new file mode 100644 index 0000000..f8c3d63 --- /dev/null +++ b/resume/migrations/0003_resume_question_chathistory.py @@ -0,0 +1,42 @@ +# Generated by Django 5.0.3 on 2024-04-10 06:52 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("resume", "0002_resume_position"), + ] + + operations = [ + migrations.AddField( + model_name="resume", + name="question", + field=models.TextField(default="테스트질문"), + preserve_default=False, + ), + migrations.CreateModel( + name="ChatHistory", + fields=[ + ( + "id", + models.BigAutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("created_at", models.DateTimeField(auto_now_add=True)), + ("updated_at", models.DateTimeField(auto_now=True)), + ( + "resume", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, to="resume.resume" + ), + ), + ], + ), + ] diff --git a/resume/migrations/0004_alter_resume_due_date.py b/resume/migrations/0004_alter_resume_due_date.py new file mode 100644 index 0000000..0ac403d --- /dev/null +++ b/resume/migrations/0004_alter_resume_due_date.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.3 on 2024-04-10 07:24 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("resume", "0003_resume_question_chathistory"), + ] + + operations = [ + migrations.AlterField( + model_name="resume", + name="due_date", + field=models.CharField(max_length=32, null=True), + ), + ] diff --git a/resume/migrations/0005_alter_resume_due_date.py b/resume/migrations/0005_alter_resume_due_date.py new file mode 100644 index 0000000..4b20200 --- /dev/null +++ b/resume/migrations/0005_alter_resume_due_date.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.3 on 2024-04-10 07:29 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("resume", "0004_alter_resume_due_date"), + ] + + operations = [ + migrations.AlterField( + model_name="resume", + name="due_date", + field=models.DateField(null=True), + ), + ] diff --git a/resume/models.py b/resume/models.py index 2bef061..60215e1 100644 --- a/resume/models.py +++ b/resume/models.py @@ -6,8 +6,9 @@ class Resume(models.Model): user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE) title = models.CharField(max_length=255) # 제목이 곧 지원하려는 기업명과 동일함 position = models.CharField(max_length=255) # 지원하려는 기업의 지원하려는 직무 - content = models.TextField() - due_date = models.DateTimeField(null=True) + question = models.TextField() # 작성하려는 자소서에서 답변할 질문 + content = models.TextField() # 질문에 대한 답변 = contents + due_date = models.DateField(null=True) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) is_finished = models.BooleanField(default=False) diff --git a/resume/serializers.py b/resume/serializers.py index 17cc067..6c6867b 100644 --- a/resume/serializers.py +++ b/resume/serializers.py @@ -17,6 +17,7 @@ class Meta: fields = ( "title", "position", + "question", "content", "due_date", "created_at", diff --git a/resume/utils.py b/resume/utils.py index 5e0ffa5..844f613 100644 --- a/resume/utils.py +++ b/resume/utils.py @@ -3,7 +3,7 @@ import environ from pinecone import Pinecone -# from utils.openai_call import get_embedding +from utils.openai_call import get_embedding from langchain_community.chat_models import ChatOpenAI from langchain.chains import ConversationChain diff --git a/resume/views.py b/resume/views.py index be94255..a56119b 100644 --- a/resume/views.py +++ b/resume/views.py @@ -106,14 +106,25 @@ class GenerateResumeView(APIView): summary="자기소개서 생성", description="답변을 기반으로 자기소개서를 생성합니다.", responses={ - 200: inline_serializer( - name="GenerateResumeResponse", - fields={ - "result": serializers.CharField(), - }, - ) + 200: PostResumeSerializer }, parameters=[ + OpenApiParameter( + name="title", + type=str, + description="자소서 제목", + ), + OpenApiParameter( + name="position", + type=str, + description="지원하려는 직무", + ), + OpenApiParameter( + name="due_date", + type=str, + style="date", + description="공고 마감기한. 그냥 str 형식으로 \"2024-04-10\" 이렇게 보내주삼", + ), OpenApiParameter( name="question", type=str, @@ -150,24 +161,14 @@ class GenerateResumeView(APIView): ], ) def post(self, request): - serializer = PostResumeSerializer(data=request.data) - - # 데이터 유효성 검사 - if serializer.is_valid(): - # 유효한 데이터의 경우, 자소서 저장 - serializer.save( - user=request.user - ) # 현재 로그인한 사용자를 메모의 user 필드에 저장 - return Response(serializer.data, status=status.HTTP_201_CREATED) - else: - # 데이터가 유효하지 않은 경우, 에러 메시지 반환 - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - - question = request.GET.get("question") - guidelines = request.GET.get("guidelines") - answers = request.GET.get("answers") - free_answer = request.GET.get("free_answer") - favor_info = request.GET.get("favor_info") + title = request.data["title"] + position = request.data["position"] + due_date = request.data["due_date"] + question = request.data["question"] + guidelines = request.data["guidelines"] + answers = request.data["answers"] + free_answer = request.data["free_answer"] + favor_info = request.data["favor_info"] # 답변을 guideline + answer + free_answer로 구성 total_answer = "" @@ -201,9 +202,27 @@ def post(self, request): # 자소서 생성 generated_self_introduction = get_chat_openai(prompt) - generated_self_introduction_json = {"result": generated_self_introduction} - return JsonResponse(generated_self_introduction_json, status=200) + serializer = PostResumeSerializer(data={ + "title": title, + "position": position, + "question": question, + "content": generated_self_introduction, + "due_date": due_date, + "is_finished": False, + "is_liked": False + }) + + # 데이터 유효성 검사 + if serializer.is_valid(): + # 유효한 데이터의 경우, 자소서 저장 + serializer.save( + user=request.user + ) # 현재 로그인한 사용자를 자소서의 user 필드에 저장 + return Response(serializer.data, status=status.HTTP_201_CREATED) + else: + # 데이터가 유효하지 않은 경우, 에러 메시지 반환 + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) class PostResumeView(APIView): @@ -320,7 +339,7 @@ def post(self, request): query = request.data.query chatbot_answer = run_llm(query=query) - return Response( + return JsonResponse( {"answer": chatbot_answer}, status=status.HTTP_200_OK, ) \ No newline at end of file From c2127268765c91b09ea14c9592e68cf1f67e1ee2 Mon Sep 17 00:00:00 2001 From: yjoonjang Date: Wed, 10 Apr 2024 16:55:52 +0900 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=ED=8A=B9=EC=A0=95=20=EC=9E=90?= =?UTF-8?q?=EC=86=8C=EC=84=9C=20=EB=B0=9B=EC=95=84=EC=98=A4=EB=8A=94=20api?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- memos/urls.py | 2 +- resume/urls.py | 3 +- resume/views.py | 87 +++++++++++++++++++++++++++++++------------------ 3 files changed, 59 insertions(+), 33 deletions(-) diff --git a/memos/urls.py b/memos/urls.py index c04ef75..d91bddf 100644 --- a/memos/urls.py +++ b/memos/urls.py @@ -5,7 +5,7 @@ urlpatterns = [ path("", views.PostMemoView.as_view(), name="post_memo"), path("all", views.GetAllMemoView.as_view(), name="get_all_memos"), - path("memo/", views.GetMemoDetailView.as_view(), name="memo-detail"), + path("", views.GetMemoDetailView.as_view(), name="memo-detail"), path("update/", views.UpdateMemoView.as_view(), name="scrap-memo"), path("delete/", views.DeleteMemoView.as_view(), name="delete-memo"), path("search", views.SearchMemoView.as_view(), name="search-memo"), diff --git a/resume/urls.py b/resume/urls.py index c06c361..34834bf 100644 --- a/resume/urls.py +++ b/resume/urls.py @@ -6,8 +6,9 @@ path("all", views.GetAllResumeView.as_view(), name="get_all_resume"), path("guidelines", views.GetGuidelinesView.as_view(), name="get_guidelines"), path("generate", views.GenerateResumeView.as_view(), name="generate_resume"), - path("", views.PostResumeView.as_view(), name="post_resume"), + # path("", views.PostResumeView.as_view(), name="post_resume"), path("update/", views.UpdateResumeView.as_view(), name="update_resume"), path("scrap/", views.ScrapResumeView.as_view(), name="scrap_resume"), path("chat", views.ChatView.as_view(), name="chat"), + path("", views.GetResumeView.as_view(), name="update_resume"), ] diff --git a/resume/views.py b/resume/views.py index a56119b..9804b36 100644 --- a/resume/views.py +++ b/resume/views.py @@ -216,51 +216,75 @@ def post(self, request): # 데이터 유효성 검사 if serializer.is_valid(): # 유효한 데이터의 경우, 자소서 저장 - serializer.save( + saved_instance = serializer.save( user=request.user ) # 현재 로그인한 사용자를 자소서의 user 필드에 저장 - return Response(serializer.data, status=status.HTTP_201_CREATED) + return Response({"id": saved_instance.id}, status=status.HTTP_201_CREATED) else: # 데이터가 유효하지 않은 경우, 에러 메시지 반환 return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) -class PostResumeView(APIView): +# class PostResumeView(APIView): +# permission_classes = [IsAuthenticated] +# +# @extend_schema( +# summary="자기소개서 등록", +# description="자기소개서를 등록합니다.", +# responses={200: PostResumeSerializer}, +# request={ +# "application/json": { +# "type": "object", +# "properties": { +# "title": {"type": "string"}, +# "position": {"type": "string"}, +# "content": {"type": "string"}, +# "due_date": {"type": "string"}, +# }, +# }, +# }, +# ) +# def post(self, request): +# serializer = PostResumeSerializer(data=request.data) +# +# # 데이터 유효성 검사 +# if serializer.is_valid(): +# # 유효한 데이터의 경우, 자소서 저장 +# serializer.save( +# user=request.user +# ) # 현재 로그인한 사용자를 메모의 user 필드에 저장 +# return Response(serializer.data, status=status.HTTP_201_CREATED) +# else: +# # 데이터가 유효하지 않은 경우, 에러 메시지 반환 +# return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + +class GetResumeView(APIView): permission_classes = [IsAuthenticated] + def get_object(self, pk, user): + try: + resume = Resume.objects.get(pk=pk) + # 메모를 작성한 유저와 현재 요청 유저가 동일한지 확인 + if resume.user != user: + raise Http404("해당 메모에 접근할 권한이 없습니다.") + return resume + except resume.DoesNotExist: + raise Http404 + @extend_schema( - summary="자기소개서 등록", - description="자기소개서를 등록합니다.", + summary="특정 자소서를 받아옵니다.", + description="사용자가 작성한 특정 자소서의 디테일을 받아옵니다.", responses={200: PostResumeSerializer}, - request={ - "application/json": { - "type": "object", - "properties": { - "title": {"type": "string"}, - "position": {"type": "string"}, - "content": {"type": "string"}, - "due_date": {"type": "string"}, - }, - }, - }, ) - def post(self, request): - serializer = PostResumeSerializer(data=request.data) - - # 데이터 유효성 검사 - if serializer.is_valid(): - # 유효한 데이터의 경우, 자소서 저장 - serializer.save( - user=request.user - ) # 현재 로그인한 사용자를 메모의 user 필드에 저장 - return Response(serializer.data, status=status.HTTP_201_CREATED) - else: - # 데이터가 유효하지 않은 경우, 에러 메시지 반환 - return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + def get(self, request, pk, format=None): + print(pk) + resume = self.get_object(pk, request.user) + serializer = PostResumeSerializer(resume) + return Response(serializer.data, status=status.HTTP_200_OK) class UpdateResumeView(APIView): - permission_classes = [IsAuthenticated] # 인증된 사용자만 접근 가능하도록 설정 + permission_classes = [IsAuthenticated] @extend_schema( summary="자기소개서 업데이트", @@ -342,4 +366,5 @@ def post(self, request): return JsonResponse( {"answer": chatbot_answer}, status=status.HTTP_200_OK, - ) \ No newline at end of file + ) +