From 4226567f5c7aa55218471c103c332ea07cf141c2 Mon Sep 17 00:00:00 2001 From: uommou Date: Sun, 7 Apr 2024 18:18:37 +0900 Subject: [PATCH 01/10] =?UTF-8?q?[feat]=20=C3=AC]=20generate=20emoji=20tha?= =?UTF-8?q?t=20represents=20today's=20schedule?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/database/chroma_db.py | 2 +- app/dto/db_dto.py | 5 ++++ app/main.py | 3 ++ app/prompt/report_prompt.py | 17 +++++++++++ app/routers/recommendation.py | 2 +- app/routers/report.py | 55 +++++++++++++++++++++++++++++++++++ 6 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 app/prompt/report_prompt.py create mode 100644 app/routers/report.py diff --git a/app/database/chroma_db.py b/app/database/chroma_db.py index 0d7e3d1..9af2466 100644 --- a/app/database/chroma_db.py +++ b/app/database/chroma_db.py @@ -57,7 +57,7 @@ async def add_db_data(schedule_data: AddScheduleDTO): # 메인페이지 한 줄 추천 기능에 사용하는 함수 # 유저의 id, 해당 날짜로 필터링 -async def db_recommendation_main(user_data: RecommendationMainRequestDTO): +async def db_daily_schedule(user_data: RecommendationMainRequestDTO): member = user_data.member_id schedule_datetime_start = user_data.schedule_datetime_start schedule_datetime_end = user_data.schedule_datetime_end diff --git a/app/dto/db_dto.py b/app/dto/db_dto.py index 8228fd5..ed7e916 100644 --- a/app/dto/db_dto.py +++ b/app/dto/db_dto.py @@ -17,3 +17,8 @@ class RecommendationMainRequestDTO(BaseModel): schedule_datetime_start: str schedule_datetime_end: str +class ReportMemoryEmojiRequestDTO(BaseModel): + member_id: int + user_persona: str + schedule_datetime_start: str + schedule_datetime_end: str diff --git a/app/main.py b/app/main.py index 523db77..2504363 100644 --- a/app/main.py +++ b/app/main.py @@ -32,6 +32,9 @@ from app.routers import recommendation app.include_router(recommendation.router) +from app.routers import report +app.include_router(report.router) + # description: prevent CORS error origins = [ "*", diff --git a/app/prompt/report_prompt.py b/app/prompt/report_prompt.py new file mode 100644 index 0000000..d1e8648 --- /dev/null +++ b/app/prompt/report_prompt.py @@ -0,0 +1,17 @@ +class Template: + memory_emoji_template = """ + You are an AI assistant designed to return an emoji that represents a user's day based on their schedule. You will receive information about the user's daily schedule. Your task is to analyze this schedule and select a single emoji that encapsulates the day's activities. There are a few guidelines you must adhere to in your selection: + + YOU MUST RESPOND WITH A SINGLE EMOJI without any additional commentary. + The emoji must reflect the overall theme or mood of the day's activities. + Your recommendation should be intuitive, making it easy for the user to see the connection between the schedule and the chosen emoji. + Example: + User schedule: [Practice guitar, Calculate accuracy, Study backend development, Run AI models in the lab, Study NEST.JS] + AI Recommendation: 🎓 + + User schedule: [Morning jog, Office work, Lunch with friends, Evening yoga] + AI Recommendation: ☀️ + + User schedule: {schedule} + AI Recommendation: + """ \ No newline at end of file diff --git a/app/routers/recommendation.py b/app/routers/recommendation.py index 2ca270f..612e658 100644 --- a/app/routers/recommendation.py +++ b/app/routers/recommendation.py @@ -38,7 +38,7 @@ async def get_recommendation(user_data: RecommendationMainRequestDTO) -> ChatRes ) # vectordb에서 유저의 정보를 가져온다. - schedule = await vectordb.db_recommendation_main(user_data) + schedule = await vectordb.db_daily_schedule(user_data) print(schedule) diff --git a/app/routers/report.py b/app/routers/report.py new file mode 100644 index 0000000..8e272f6 --- /dev/null +++ b/app/routers/report.py @@ -0,0 +1,55 @@ +import configparser +import os + +from dotenv import load_dotenv +from fastapi import APIRouter, Depends, status, HTTPException +from langchain_community.chat_models import ChatOpenAI +from langchain_core.prompts import PromptTemplate + +from app.dto.db_dto import ReportMemoryEmojiRequestDTO +from app.dto.openai_dto import ChatResponse +from app.prompt import report_prompt +import app.database.chroma_db as vectordb + +router = APIRouter( + prefix="/report", + tags=["report"] +) + +# description: load env variables from .env file +load_dotenv() +OPENAI_API_KEY = os.getenv("OPENAI_API_KEY") + +# description: load config variables from openai_config.ini file +CONFIG_FILE_PATH = "app/prompt/openai_config.ini" +config = configparser.ConfigParser() +config.read(CONFIG_FILE_PATH) + +@router.post("/memory_emoji", status_code=status.HTTP_200_OK) +async def get_memory_emoji(user_data: ReportMemoryEmojiRequestDTO) -> ChatResponse: + try: + # 모델 + config_report_emoji = config['NESS_RECOMMENDATION'] + + chat_model = ChatOpenAI(temperature=config_report_emoji['TEMPERATURE'], # 창의성 (0.0 ~ 2.0) + max_tokens=config_report_emoji['MAX_TOKENS'], # 최대 토큰수 + model_name=config_report_emoji['MODEL_NAME'], # 모델명 + openai_api_key=OPENAI_API_KEY # API 키 + ) + + # vectordb에서 유저의 정보를 가져온다. + schedule = await vectordb.db_daily_schedule(user_data) + + print(schedule) + + # 템플릿 + memory_emoji_template = report_prompt.Template.memory_emoji_template + + prompt = PromptTemplate.from_template(memory_emoji_template) + result = chat_model.predict(prompt.format(output_language="Korean", schedule=schedule)) + print(result) + return ChatResponse(ness=result) + + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) + From a2bab8b3bad48cf8963b814e1ccbbfa78991e4c2 Mon Sep 17 00:00:00 2001 From: uommou Date: Sun, 7 Apr 2024 18:53:23 +0900 Subject: [PATCH 02/10] [feat] tag generation rough sketch --- app/database/chroma_db.py | 22 +++++++++++++++++++++- app/dto/db_dto.py | 7 +++++++ app/routers/report.py | 29 ++++++++++++++++++++++++++++- 3 files changed, 56 insertions(+), 2 deletions(-) diff --git a/app/database/chroma_db.py b/app/database/chroma_db.py index 9af2466..4938ed9 100644 --- a/app/database/chroma_db.py +++ b/app/database/chroma_db.py @@ -10,7 +10,7 @@ import os import datetime from dotenv import load_dotenv -from app.dto.db_dto import AddScheduleDTO, RecommendationMainRequestDTO +from app.dto.db_dto import AddScheduleDTO, RecommendationMainRequestDTO, ReportTagsRequestDTO load_dotenv() CHROMA_DB_IP_ADDRESS = os.getenv("CHROMA_DB_IP_ADDRESS") @@ -76,5 +76,25 @@ async def db_daily_schedule(user_data: RecommendationMainRequestDTO): ) return results['documents'] +# 태그 생성용 스케쥴 반환 - 카테고리에 따라 +async def db_monthly_tag_schedule(user_data: ReportTagsRequestDTO): + member = user_data.member_id + schedule_datetime_start = user_data.schedule_datetime_start + schedule_datetime_end = user_data.schedule_datetime_end + schedule_date = schedule_datetime_start.split("T")[0] + persona = user_data.user_persona or "hard working" + results = schedules.query( + query_texts=[persona], + n_results=5, + where={"$and": + [ + {"member": {"$eq": int(member)}}, + {"date": {"$eq": schedule_date}} + ] + } + # where_document={"$contains":"search_string"} # optional filter + ) + return results['documents'] + def get_chroma_client(): return chroma_client \ No newline at end of file diff --git a/app/dto/db_dto.py b/app/dto/db_dto.py index ed7e916..1f85ab9 100644 --- a/app/dto/db_dto.py +++ b/app/dto/db_dto.py @@ -22,3 +22,10 @@ class ReportMemoryEmojiRequestDTO(BaseModel): user_persona: str schedule_datetime_start: str schedule_datetime_end: str + +class ReportTagsRequestDTO(BaseModel): + member_id: int + user_persona: str + schedule_datetime_start: str + schedule_datetime_end: str + diff --git a/app/routers/report.py b/app/routers/report.py index 8e272f6..b4e248e 100644 --- a/app/routers/report.py +++ b/app/routers/report.py @@ -6,7 +6,7 @@ from langchain_community.chat_models import ChatOpenAI from langchain_core.prompts import PromptTemplate -from app.dto.db_dto import ReportMemoryEmojiRequestDTO +from app.dto.db_dto import ReportMemoryEmojiRequestDTO, ReportTagsRequestDTO from app.dto.openai_dto import ChatResponse from app.prompt import report_prompt import app.database.chroma_db as vectordb @@ -53,3 +53,30 @@ async def get_memory_emoji(user_data: ReportMemoryEmojiRequestDTO) -> ChatRespon except Exception as e: raise HTTPException(status_code=500, detail=str(e)) +@router.post("/tags", status_code=status.HTTP_200_OK) +async def get_tags(user_data: ReportTagsRequestDTO) -> ChatResponse: + try: + # 모델 + config_tags = config['NESS_RECOMMENDATION'] + + chat_model = ChatOpenAI(temperature=config_tags['TEMPERATURE'], # 창의성 (0.0 ~ 2.0) + max_tokens=config_tags['MAX_TOKENS'], # 최대 토큰수 + model_name=config_tags['MODEL_NAME'], # 모델명 + openai_api_key=OPENAI_API_KEY # API 키 + ) + + # vectordb에서 유저의 정보를 가져온다. + schedule = await vectordb.db_monthly_tag_schedule(user_data) + + print(schedule) + + # 템플릿 + memory_emoji_template = report_prompt.Template.memory_emoji_template + + prompt = PromptTemplate.from_template(memory_emoji_template) + result = chat_model.predict(prompt.format(output_language="Korean", schedule=schedule)) + print(result) + return ChatResponse(ness=result) + + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) \ No newline at end of file From 68d36efdcbbd7b90205de97ac637f2df351f3945 Mon Sep 17 00:00:00 2001 From: uommou Date: Sun, 7 Apr 2024 19:48:47 +0900 Subject: [PATCH 03/10] [feat] report tags complete: added db metadatas, changed db query logic --- app/database/chroma_db.py | 25 +++++++++++++++++++++---- app/dto/openai_dto.py | 5 ++++- app/prompt/openai_config.ini | 7 ++++++- app/prompt/report_prompt.py | 18 ++++++++++++++++++ app/routers/report.py | 15 +++++++++------ 5 files changed, 58 insertions(+), 12 deletions(-) diff --git a/app/database/chroma_db.py b/app/database/chroma_db.py index 4938ed9..2351fee 100644 --- a/app/database/chroma_db.py +++ b/app/database/chroma_db.py @@ -48,10 +48,13 @@ async def search_db_query(query): # 스프링 백엔드로부터 chroma DB에 저장할 데이터를 받아 DB에 추가한다. async def add_db_data(schedule_data: AddScheduleDTO): schedule_date = schedule_data.schedule_datetime_start.split("T")[0] + year = int(schedule_date.split("-")[0]) + month = int(schedule_date.split("-")[1]) + date = int(schedule_date.split("-")[2]) schedules.add( documents=[schedule_data.data], ids=[str(schedule_data.schedule_id)], - metadatas=[{"date": schedule_date, "datetime_start": schedule_data.schedule_datetime_start, "datetime_end": schedule_data.schedule_datetime_end, "member": schedule_data.member_id, "category": schedule_data.category, "location": schedule_data.location, "person": schedule_data.person}] + metadatas=[{"year": year, "month": month, "date": date, "datetime_start": schedule_data.schedule_datetime_start, "datetime_end": schedule_data.schedule_datetime_end, "member": schedule_data.member_id, "category": schedule_data.category, "location": schedule_data.location, "person": schedule_data.person}] ) return True @@ -62,6 +65,9 @@ async def db_daily_schedule(user_data: RecommendationMainRequestDTO): schedule_datetime_start = user_data.schedule_datetime_start schedule_datetime_end = user_data.schedule_datetime_end schedule_date = schedule_datetime_start.split("T")[0] + year = int(schedule_date.split("-")[0]) + month = int(schedule_date.split("-")[1]) + date = int(schedule_date.split("-")[2]) persona = user_data.user_persona or "hard working" results = schedules.query( query_texts=[persona], @@ -69,7 +75,9 @@ async def db_daily_schedule(user_data: RecommendationMainRequestDTO): where={"$and": [ {"member": {"$eq": int(member)}}, - {"date": {"$eq": schedule_date}} + {"year": {"$eq": year}}, + {"month": {"$eq": month}}, + {"date": {"$eq": date}} ] } # where_document={"$contains":"search_string"} # optional filter @@ -82,14 +90,23 @@ async def db_monthly_tag_schedule(user_data: ReportTagsRequestDTO): schedule_datetime_start = user_data.schedule_datetime_start schedule_datetime_end = user_data.schedule_datetime_end schedule_date = schedule_datetime_start.split("T")[0] + year = int(schedule_date.split("-")[0]) + month = int(schedule_date.split("-")[1]) + date = int(schedule_date.split("-")[2]) persona = user_data.user_persona or "hard working" results = schedules.query( query_texts=[persona], - n_results=5, + n_results=15, where={"$and": [ {"member": {"$eq": int(member)}}, - {"date": {"$eq": schedule_date}} + {"year": {"$eq": year}}, + {"$or": + [{"$and": + [{"month": {"$eq": month-1}}, {"date": {"$gte": 10}}]}, + {"$and": + [{"month": {"$eq": month}}, {"date": {"$lt": 10}}]} + ]} ] } # where_document={"$contains":"search_string"} # optional filter diff --git a/app/dto/openai_dto.py b/app/dto/openai_dto.py index cfa374f..f002b2a 100644 --- a/app/dto/openai_dto.py +++ b/app/dto/openai_dto.py @@ -9,4 +9,7 @@ class ChatResponse(BaseModel): class ChatCaseResponse(BaseModel): ness: str - case: int \ No newline at end of file + case: int + +class TagsResponse(BaseModel): + tags: list \ No newline at end of file diff --git a/app/prompt/openai_config.ini b/app/prompt/openai_config.ini index 8a62d43..3627abb 100644 --- a/app/prompt/openai_config.ini +++ b/app/prompt/openai_config.ini @@ -11,4 +11,9 @@ MODEL_NAME = gpt-4 [NESS_RECOMMENDATION] TEMPERATURE = 0 MAX_TOKENS = 2048 -MODEL_NAME = gpt-3.5-turbo-1106 \ No newline at end of file +MODEL_NAME = gpt-3.5-turbo-1106 + +[NESS_TAGS] +TEMPERATURE = 0 +MAX_TOKENS = 2048 +MODEL_NAME = gpt-4 \ No newline at end of file diff --git a/app/prompt/report_prompt.py b/app/prompt/report_prompt.py index d1e8648..db30572 100644 --- a/app/prompt/report_prompt.py +++ b/app/prompt/report_prompt.py @@ -14,4 +14,22 @@ class Template: User schedule: {schedule} AI Recommendation: + """ + + report_tags_template = """ + You are an AI assistant tasked with analyzing a user's schedule over the span of a month. From this detailed schedule, you will distill three keywords that best encapsulate the user's activities, interests, or achievements throughout the month. These keywords should not only reflect the user's endeavors but also convey a sense of accomplishment and enjoyment. Your output should be engaging, showcasing your wit and unique perspective. Here are the rules for your analysis: + + YOU MUST USE {output_language} TO RESPOND TO THE INPUT. + YOU MUST PROVIDE THREE KEYWORDS in your response. Each keyword should be a single word or a concise phrase. + The keywords must capture the essence of the user's monthly activities, highlighting aspects that are both rewarding and enjoyable. + Your selections should be creative and personalized, aiming to reflect the user's unique experiences over the month. + Example: + User's monthly schedule: [Attended a programming bootcamp, Completed a marathon, Read three novels, Volunteered at the local food bank, Started a blog about sustainability] + AI Recommendation: "공부 매니아, 환경 지킴이, 자기 계발 홀릭" + + User's monthly schedule: [Took photography classes, Explored three new hiking trails, Organized a neighborhood clean-up, Experimented with vegan recipes] + AI Recommendation: "모험가, 미식가, 도파민 중독자" + + User's monthly schedule: {schedule} + AI Recommendation: """ \ No newline at end of file diff --git a/app/routers/report.py b/app/routers/report.py index b4e248e..dc295f3 100644 --- a/app/routers/report.py +++ b/app/routers/report.py @@ -7,7 +7,7 @@ from langchain_core.prompts import PromptTemplate from app.dto.db_dto import ReportMemoryEmojiRequestDTO, ReportTagsRequestDTO -from app.dto.openai_dto import ChatResponse +from app.dto.openai_dto import ChatResponse, TagsResponse from app.prompt import report_prompt import app.database.chroma_db as vectordb @@ -54,10 +54,10 @@ async def get_memory_emoji(user_data: ReportMemoryEmojiRequestDTO) -> ChatRespon raise HTTPException(status_code=500, detail=str(e)) @router.post("/tags", status_code=status.HTTP_200_OK) -async def get_tags(user_data: ReportTagsRequestDTO) -> ChatResponse: +async def get_tags(user_data: ReportTagsRequestDTO) -> TagsResponse: try: # 모델 - config_tags = config['NESS_RECOMMENDATION'] + config_tags = config['NESS_TAGS'] chat_model = ChatOpenAI(temperature=config_tags['TEMPERATURE'], # 창의성 (0.0 ~ 2.0) max_tokens=config_tags['MAX_TOKENS'], # 최대 토큰수 @@ -71,12 +71,15 @@ async def get_tags(user_data: ReportTagsRequestDTO) -> ChatResponse: print(schedule) # 템플릿 - memory_emoji_template = report_prompt.Template.memory_emoji_template + report_tags_template = report_prompt.Template.report_tags_template - prompt = PromptTemplate.from_template(memory_emoji_template) + prompt = PromptTemplate.from_template(report_tags_template) result = chat_model.predict(prompt.format(output_language="Korean", schedule=schedule)) print(result) - return ChatResponse(ness=result) + tags = result.split("\"")[1].split(",") + tags = [tag.strip() for tag in tags] + print(tags) + return TagsResponse(tags=tags) except Exception as e: raise HTTPException(status_code=500, detail=str(e)) \ No newline at end of file From 7f320f2c40827cd123047f17c58d701540b825c2 Mon Sep 17 00:00:00 2001 From: uommou Date: Sun, 7 Apr 2024 20:03:04 +0900 Subject: [PATCH 04/10] =?UTF-8?q?[hotfix]=2010=EC=9D=BC=20=EA=B8=B0?= =?UTF-8?q?=EC=A4=80=20=EC=A1=B0=ED=9A=8C=EB=A5=BC=201=EC=9D=BC=20?= =?UTF-8?q?=EA=B8=B0=EC=A4=80=EC=9C=BC=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/database/chroma_db.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/app/database/chroma_db.py b/app/database/chroma_db.py index 2351fee..a54f229 100644 --- a/app/database/chroma_db.py +++ b/app/database/chroma_db.py @@ -101,12 +101,13 @@ async def db_monthly_tag_schedule(user_data: ReportTagsRequestDTO): [ {"member": {"$eq": int(member)}}, {"year": {"$eq": year}}, - {"$or": - [{"$and": - [{"month": {"$eq": month-1}}, {"date": {"$gte": 10}}]}, - {"$and": - [{"month": {"$eq": month}}, {"date": {"$lt": 10}}]} - ]} + {"month": {"$eq": month - 1}} + # {"$or": + # [{"$and": + # [{"month": {"$eq": month-1}}, {"date": {"$gte": 10}}]}, + # {"$and": + # [{"month": {"$eq": month}}, {"date": {"$lt": 10}}]} + # ]} ] } # where_document={"$contains":"search_string"} # optional filter From 836d5907cc814ebedb3367cde6e64388c26ba2e7 Mon Sep 17 00:00:00 2001 From: uommou Date: Fri, 12 Apr 2024 20:43:28 +0900 Subject: [PATCH 05/10] =?UTF-8?q?[fix]=20recommendation=20=ED=94=84?= =?UTF-8?q?=EB=A1=AC=ED=94=84=ED=8A=B8=20=EB=B0=8F=20temperature=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 20자 이하로 제한 2. 문장 부호 제한 3. 모델 변경 및 창의성 증가 --- app/prompt/openai_config.ini | 4 ++-- app/prompt/openai_prompt.py | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/prompt/openai_config.ini b/app/prompt/openai_config.ini index 3627abb..315e039 100644 --- a/app/prompt/openai_config.ini +++ b/app/prompt/openai_config.ini @@ -9,9 +9,9 @@ MAX_TOKENS = 2048 MODEL_NAME = gpt-4 [NESS_RECOMMENDATION] -TEMPERATURE = 0 +TEMPERATURE = 1 MAX_TOKENS = 2048 -MODEL_NAME = gpt-3.5-turbo-1106 +MODEL_NAME = gpt-4 [NESS_TAGS] TEMPERATURE = 0 diff --git a/app/prompt/openai_prompt.py b/app/prompt/openai_prompt.py index e17f97d..0adddbe 100644 --- a/app/prompt/openai_prompt.py +++ b/app/prompt/openai_prompt.py @@ -2,12 +2,14 @@ class Template: recommendation_template = """ You are an AI assistant designed to recommend daily activities based on a user's schedule. You will receive a day's worth of the user's schedule information. Your task is to understand that schedule and, based on it, recommend an activity for the user to perform that day. There are a few rules you must follow in your recommendations: 1. YOU MUST USE {output_language} TO RESPOND TO THE USER INPUT. - 2. Ensure your recommendation is encouraging, so the user doesn't feel compelled. + 2. Ensure your recommendation is encouraging and delicate, so the user doesn't feel compelled. 3. The recommendation must be concise, limited to one sentence without any additional commentary. + 4. The recommendation must not exceed 20 characters in the {output_language}. + 5. The final punctuation of the recommendation must be exclusively an exclamation point or a question mark. Example: User schedule: [Practice guitar, Calculate accuracy, Study backend development, Run AI models in the lab, Study NEST.JS] - AI Recommendation: "Your day is filled with learning and research. how about taking a short walk in between studies?" + AI Recommendation: "공부 사이에 짧게 산책 어때요?" User schedule: {schedule} AI Recommendation: From a8cfddd170301dd57a6e9849466623afbe9accd7 Mon Sep 17 00:00:00 2001 From: uommou Date: Fri, 12 Apr 2024 21:13:23 +0900 Subject: [PATCH 06/10] =?UTF-8?q?[fix]=20=ED=94=84=EB=A1=AC=ED=94=84?= =?UTF-8?q?=ED=8A=B8=20=EC=88=98=EC=A0=95=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/prompt/openai_config.ini | 2 +- app/prompt/report_prompt.py | 33 +++++++++++++++++---------------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/app/prompt/openai_config.ini b/app/prompt/openai_config.ini index 315e039..2739e3f 100644 --- a/app/prompt/openai_config.ini +++ b/app/prompt/openai_config.ini @@ -14,6 +14,6 @@ MAX_TOKENS = 2048 MODEL_NAME = gpt-4 [NESS_TAGS] -TEMPERATURE = 0 +TEMPERATURE = 0.5 MAX_TOKENS = 2048 MODEL_NAME = gpt-4 \ No newline at end of file diff --git a/app/prompt/report_prompt.py b/app/prompt/report_prompt.py index db30572..a739cc1 100644 --- a/app/prompt/report_prompt.py +++ b/app/prompt/report_prompt.py @@ -17,19 +17,20 @@ class Template: """ report_tags_template = """ - You are an AI assistant tasked with analyzing a user's schedule over the span of a month. From this detailed schedule, you will distill three keywords that best encapsulate the user's activities, interests, or achievements throughout the month. These keywords should not only reflect the user's endeavors but also convey a sense of accomplishment and enjoyment. Your output should be engaging, showcasing your wit and unique perspective. Here are the rules for your analysis: - - YOU MUST USE {output_language} TO RESPOND TO THE INPUT. - YOU MUST PROVIDE THREE KEYWORDS in your response. Each keyword should be a single word or a concise phrase. - The keywords must capture the essence of the user's monthly activities, highlighting aspects that are both rewarding and enjoyable. - Your selections should be creative and personalized, aiming to reflect the user's unique experiences over the month. - Example: - User's monthly schedule: [Attended a programming bootcamp, Completed a marathon, Read three novels, Volunteered at the local food bank, Started a blog about sustainability] - AI Recommendation: "공부 매니아, 환경 지킴이, 자기 계발 홀릭" - - User's monthly schedule: [Took photography classes, Explored three new hiking trails, Organized a neighborhood clean-up, Experimented with vegan recipes] - AI Recommendation: "모험가, 미식가, 도파민 중독자" - - User's monthly schedule: {schedule} - AI Recommendation: - """ \ No newline at end of file + You are an AI assistant tasked with analyzing a user's schedule over the span of a month. From this detailed schedule, you will distill three keywords that best encapsulate the user's activities, interests, or achievements throughout the month. Additionally, you will provide a brief explanation for each keyword to illustrate why it was chosen, making the output more informative and engaging. Here are the rules for your analysis: + + YOU MUST USE {output_language} TO RESPOND TO THE INPUT. + YOU MUST PROVIDE THREE KEYWORDS in your response, each accompanied by a concise explanation. + The keywords must capture the essence of the user's monthly activities, highlighting aspects that are both rewarding and enjoyable. + Your selections should be creative and personalized, aiming to reflect the user's unique experiences over the month. + Each explanation of the keywords must not exceed 50 characters in the {output_language}. + Example: + User's monthly schedule: [Attended a programming bootcamp, Completed a marathon, Read three novels, Volunteered at the local food bank, Started a blog about sustainability] + AI Recommendation: "공부 매니아: 이번 달엔 공부를 정말 많이 하셨군요!, 환경 지킴이: 지속 가능한 생활에 대한 열정이 느껴져요., 자기 계발 홀릭: 성장을 위해 노력하는 모습이 멋져요." + + User's monthly schedule: [Took photography classes, Explored three new hiking trails, Organized a neighborhood clean-up, Experimented with vegan recipes] + AI Recommendation: "모험가: 새로운 활동에 많이 도전하셨네요!, 미식가: 레시피 실험을 했다니 멋져요., 도파민 중독자: 즐거운 일을 많이 만드시네요!" + + User's monthly schedule: {schedule} + AI Recommendation: + """ From c2acb680e5d67cda7a538c19cc6608b2b542df1e Mon Sep 17 00:00:00 2001 From: uommou Date: Fri, 12 Apr 2024 21:25:50 +0900 Subject: [PATCH 07/10] =?UTF-8?q?[fix]=20=EB=A6=AC=ED=84=B4=EC=97=90=20des?= =?UTF-8?q?cription=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/dto/openai_dto.py | 8 ++++++-- app/routers/report.py | 17 ++++++++++++----- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/app/dto/openai_dto.py b/app/dto/openai_dto.py index f002b2a..824c603 100644 --- a/app/dto/openai_dto.py +++ b/app/dto/openai_dto.py @@ -1,5 +1,5 @@ from pydantic import BaseModel - +from typing import List class PromptRequest(BaseModel): prompt: str @@ -11,5 +11,9 @@ class ChatCaseResponse(BaseModel): ness: str case: int +class TagDescription(BaseModel): + tag: str + desc: str + class TagsResponse(BaseModel): - tags: list \ No newline at end of file + tagList: List[TagDescription] \ No newline at end of file diff --git a/app/routers/report.py b/app/routers/report.py index dc295f3..2b92bdc 100644 --- a/app/routers/report.py +++ b/app/routers/report.py @@ -7,7 +7,7 @@ from langchain_core.prompts import PromptTemplate from app.dto.db_dto import ReportMemoryEmojiRequestDTO, ReportTagsRequestDTO -from app.dto.openai_dto import ChatResponse, TagsResponse +from app.dto.openai_dto import ChatResponse, TagsResponse, TagDescription from app.prompt import report_prompt import app.database.chroma_db as vectordb @@ -76,10 +76,17 @@ async def get_tags(user_data: ReportTagsRequestDTO) -> TagsResponse: prompt = PromptTemplate.from_template(report_tags_template) result = chat_model.predict(prompt.format(output_language="Korean", schedule=schedule)) print(result) - tags = result.split("\"")[1].split(",") - tags = [tag.strip() for tag in tags] - print(tags) - return TagsResponse(tags=tags) + + # 문자열 파싱해서 dto로 매핑 + tag_entries = result.split("\"")[1].split(", ") + tags = [] + + for entry in tag_entries: + # ':'를 기준으로 태그와 설명을 분리 + tag, desc = entry.split(": ") + tags.append(TagDescription(tag=tag.strip(), desc=desc.strip())) + + return TagsResponse(tagList=tags) except Exception as e: raise HTTPException(status_code=500, detail=str(e)) \ No newline at end of file From cbc386d3470f6da81ad31c4aab7661fa58467c6a Mon Sep 17 00:00:00 2001 From: uommou Date: Sun, 14 Apr 2024 15:45:04 +0900 Subject: [PATCH 08/10] =?UTF-8?q?[hotfix]=20db=20=EC=9E=90=EB=A3=8C?= =?UTF-8?q?=ED=98=95=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/dto/db_dto.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/dto/db_dto.py b/app/dto/db_dto.py index 1f85ab9..f6fef84 100644 --- a/app/dto/db_dto.py +++ b/app/dto/db_dto.py @@ -7,7 +7,7 @@ class AddScheduleDTO(BaseModel): schedule_datetime_end: str schedule_id: int member_id: int - category: str + category: int location: str person: str From 50c32e56e6f58fd6c6728a78cd671a0aeeee8e78 Mon Sep 17 00:00:00 2001 From: uommou Date: Sun, 14 Apr 2024 16:29:22 +0900 Subject: [PATCH 09/10] =?UTF-8?q?[fix]=20=EB=8D=B0=EB=AA=A8=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=20=EA=B8=B0=EC=A4=80=EC=9C=BC=EB=A1=9C=20=EC=B1=84?= =?UTF-8?q?=ED=8C=85=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/prompt/openai_config.ini | 4 ++-- app/prompt/openai_prompt.py | 2 ++ app/routers/chat.py | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/app/prompt/openai_config.ini b/app/prompt/openai_config.ini index 2739e3f..70ee694 100644 --- a/app/prompt/openai_config.ini +++ b/app/prompt/openai_config.ini @@ -1,7 +1,7 @@ [NESS_NORMAL] -TEMPERATURE = 0 +TEMPERATURE = 0.5 MAX_TOKENS = 2048 -MODEL_NAME = gpt-3.5-turbo-1106 +MODEL_NAME = gpt-4 [NESS_CASE] TEMPERATURE = 0 diff --git a/app/prompt/openai_prompt.py b/app/prompt/openai_prompt.py index 0adddbe..4ab48c7 100644 --- a/app/prompt/openai_prompt.py +++ b/app/prompt/openai_prompt.py @@ -79,6 +79,8 @@ class Template: }} User input: {question} + + Response to user: """ case3_template = """ diff --git a/app/routers/chat.py b/app/routers/chat.py index 400ded8..d169e55 100644 --- a/app/routers/chat.py +++ b/app/routers/chat.py @@ -30,7 +30,7 @@ async def get_langchain_case(data: PromptRequest) -> ChatCaseResponse: # description: use langchain - config_chat = config['NESS_CHAT'] + config_chat = config['NESS_CASE'] chat_model = ChatOpenAI(temperature=config_chat['TEMPERATURE'], # 창의성 (0.0 ~ 2.0) max_tokens=config_chat['MAX_TOKENS'], # 최대 토큰수 From 4b0194645a7799b0cf533526a03faeac502ada97 Mon Sep 17 00:00:00 2001 From: uommou Date: Sun, 14 Apr 2024 18:11:45 +0900 Subject: [PATCH 10/10] =?UTF-8?q?[fix]=20chat2=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=ED=98=84=EC=9E=AC=20=EC=8B=9C=EA=B0=84=20=EA=B8=B0=EC=A4=80=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/prompt/openai_prompt.py | 53 +++++++++++++++++++------------------ app/routers/chat.py | 12 ++++++--- 2 files changed, 35 insertions(+), 30 deletions(-) diff --git a/app/prompt/openai_prompt.py b/app/prompt/openai_prompt.py index 4ab48c7..b37762e 100644 --- a/app/prompt/openai_prompt.py +++ b/app/prompt/openai_prompt.py @@ -50,38 +50,39 @@ class Template: Answer: """ case1_template = """ - You are a friendly assistant who helps users manage their schedules. Respond kindly to the user's input. YOU MUST USE {output_language} TO RESPOND TO THE USER INPUT. - User input: {question} - """ + You are a friendly assistant, NESS. NESS helps users manage their schedules. Respond kindly to the user's input. YOU MUST USE {output_language} TO RESPOND TO THE USER INPUT. + User input: {question} + """ case2_template = """ - You are a friendly assistant who helps users manage their schedules. The user's input contains information about a new event they want to add to their schedule. You have two tasks to perform: + You are a friendly assistant who helps users manage their schedules. The user's input contains information about a new event they want to add to their schedule. You have two tasks to perform: - 1. Respond kindly to the user's input. YOU MUST USE {output_language} TO RESPOND TO THE USER INPUT. - 2. Organize the event the user wants to add into a json format for saving in a database. The returned json will have keys for info, location, person, and date. - - info: Summarizes what the user wants to do. This value must always be present. - - location: If the user's event information includes a place, save that place as the value. - - person: If the user's event mentions a person they want to include, save that person as the value. - - date: If the user's event information includes a specific date and time, save that date and time in datetime format. - Separate the outputs for tasks 1 and 2 with a special token . + 1. Respond kindly to the user's input. YOU MUST USE {output_language} TO RESPOND TO THE USER INPUT. + 2. Organize the event the user wants to add into a json format for saving in a database. The returned json will have keys for info, location, person, and date. + - info: Summarizes what the user wants to do. This value must always be present. + - location: If the user's event information includes a place, save that place as the value. + - person: If the user's event mentions a person they want to include, save that person as the value. + - date: If the user's event information includes a specific date and time, save that date and time in datetime format. Dates should be organized based on the current time at the user's location. Current time is {current_time}. + Separate the outputs for tasks 1 and 2 with a special token . - Example for one-shot learning: + Example for one-shot learning: - User input: "I have a meeting with Dr. Smith at her office on March 3rd at 10am." + User input: "I have a meeting with Dr. Smith at her office on March 3rd at 10am." - Response to user: - "I've added your meeting with Dr. Smith at her office on March 3rd at 10am to your schedule. Is there anything else you'd like to add or modify?" - - {{ - "info": "meeting with Dr. Smith", - "location": "Dr. Smith's office", - "person": "Dr. Smith", - "date": "2023-03-03T10:00:00" - }} + Response to user: + "I've added your meeting with Dr. Smith at her office on March 3rd at 10am to your schedule. Is there anything else you'd like to add or modify?" + + {{ + "info": "meeting with Dr. Smith", + "location": "Dr. Smith's office", + "person": "Dr. Smith", + "date": "2023-03-03T10:00:00" + }} + + User input: {question} + + Response to user: + """ - User input: {question} - - Response to user: - """ case3_template = """ You are an advanced, friendly assistant dedicated to helping users efficiently manage their schedules and navigate their day-to-day tasks with ease. Your primary role is to interact with users in a supportive and courteous manner, ensuring they feel valued and assisted at every step. diff --git a/app/routers/chat.py b/app/routers/chat.py index d169e55..2c9c437 100644 --- a/app/routers/chat.py +++ b/app/routers/chat.py @@ -6,6 +6,7 @@ from fastapi import APIRouter, HTTPException, status from langchain_community.chat_models import ChatOpenAI from langchain_core.prompts import PromptTemplate +from datetime import datetime from app.dto.openai_dto import PromptRequest, ChatResponse, ChatCaseResponse from app.prompt import openai_prompt @@ -57,9 +58,11 @@ async def get_langchain_case(data: PromptRequest) -> ChatCaseResponse: response = await get_langchain_rag(data) else: - print("wrong case classification") - # 적절한 HTTP 상태 코드와 함께 오류 메시지를 반환하거나, 다른 처리를 할 수 있습니다. - raise HTTPException(status_code=400, detail="Wrong case classification") + # print("wrong case classification") + # # 적절한 HTTP 상태 코드와 함께 오류 메시지를 반환하거나, 다른 처리를 할 수 있습니다. + # raise HTTPException(status_code=400, detail="Wrong case classification") + response = "좀 더 명확한 요구가 필요해요. 다시 한 번 얘기해주실 수 있나요?" + case = "Exception" return ChatCaseResponse(ness=response, case=case) @@ -104,7 +107,8 @@ async def get_langchain_schedule(data: PromptRequest): case2_template = openai_prompt.Template.case2_template prompt = PromptTemplate.from_template(case2_template) - response = chat_model.predict(prompt.format(output_language="Korean", question=question)) + current_time = datetime.now() + response = chat_model.predict(prompt.format(output_language="Korean", question=question, current_time=current_time)) print(response) return response