From 17eb257f34519ef7f1325d9455a399649063841b Mon Sep 17 00:00:00 2001 From: kth0910 Date: Thu, 10 Apr 2025 15:07:06 +0900 Subject: [PATCH 01/31] =?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(=EA=B8=B8=EC=9D=B4=20=EA=B0=90?= =?UTF-8?q?=EB=9F=89=20=ED=9B=84=20=ED=85=8C=EC=8A=A4=ED=8A=B8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chatbot.py | 192 +++++++++++++++++++++++++------------------------ 1 file changed, 97 insertions(+), 95 deletions(-) diff --git a/src/chatbot.py b/src/chatbot.py index acea639..01a8d90 100644 --- a/src/chatbot.py +++ b/src/chatbot.py @@ -1,4 +1,3 @@ -import torch from datetime import datetime, timezone, timedelta from transformers import AutoTokenizer, AutoModelForCausalLM import re @@ -7,111 +6,114 @@ from model_create import return_model_tokenizer from logger import print_log -from api_processor import put_user_histories SYSTEM_PROMPT = [ {"role": "system", "content": """ - 당신은 친절한 건강 관리 챗봇입니다. 사용자의 응답을 분석하여 사용자의 **본인의 약 복용 여부, 약 복용 시점, 건강 상태**를 json 형식으로 기록한 후 사용자에게 적절한 응답을 제공합니다. - 반드시 "" 형식으로만 답하고, 이 태그를 제거하거나 태그 외에서 임의의 문자열을 생성하지 마세요. - json 데이터는 태그안에, 사용자에게 주는 응답은 태그 안에 표시합니다. - - 다음은 json의 각 key에 대한 설명입니다. - - "약 복용 여부": 사용자가 본인의 약 복용 여부를 명확히 언급했다면 true 또는 false, 그렇지 않으면 null으로 기록하세요. - - 사용자가 언급한 약 복용 여부에 대한 표현은 다음과 같은 예시대로 처리합니다. - - "나 오늘 약 먹었수": "true" - - "이 약이 그리 좋다냐?": "false" - - "영감, 약 드슈!": "false" - - - "약 복용일": 사용자가 복용일과 관련된 내용을 언급했으면 언제 먹었는지에 대해 며칠 전인지 정수로 기록하세요. 언급이 없거나 명확히 파악할 수 없으면 null으로 기록하세요. - - 사용자가 언급한 날짜 표현은 다음과 같은 예시대로 처리합니다. - - "오늘": 0 - - "어제": -1 - - "이틀 전": -2 - - "N일 전": -N - - "N주일 전": -7*N - - - "약 복용 시간(절대)": 사용자가 복용 시간에 대해 정확한 시간을 언급했으면 몇 시에 먹었는지 기록하세요. 언급이 없거나 명확히 파악할 수 없으면 null으로 기록하세요. - - 사용자가 언급한 절대적인 시간 표현은 다음과 같은 예시대로 처리합니다. - - "1시": "1:00" - - "2시 30분": "2:30" - - "11시 59분": "11:59" - - "아침": "7:00" - - "점심": "13:00" - - "저녁": "19:00" - - - "약 복용 시간(상대)": 사용자가 복용 시간에 대해 정확하진 않지만 몇 시간 전, 몇 분 전과 같은 상대적인 시간으로 답했다면 몇 시간 몇 분 전인지 추출해서 기록하세요. 언급이 없거나 명확히 파악할 수 없으면 null으로 기록하세요. - - 사용자가 언급한 상대적인 시간 표현은 다음과 같은 예시대로 처리합니다. - - "1시간 전": "-1:00" - - "2시간 30분 전": "-2:30" - - "11시간 59분 전": "-11:59" - - - "건강 상태": 사용자가 건강 상태를 언급했으면 다음 기준에 따라 기록하세요. 언급이 없거나 명확히 파악할 수 없으면 null으로 기록하세요. - - 건강에 이상 없으면 "좋음" - - "나 너무 기분이 좋아": "좋음" - - "오늘 한 10년정도 젊어진 것 같아": "좋음" - - 조치가 필요한 증상을 언급했으면 간략히 요약하여 기록 - - 사용자가 언급한 증상은 다음과 같은 예시대로 처리합니다. - - "나 가슴이 너무 답답해": "가슴 답답함" - - "코에서 피가 나": "코피" - - "기침도 나고 콧물도 나": "콧물, 기침" - - - "추가 질문 여부" - - 사용자가 당신이 수집해야 하는 필수적인 정보를 언급하지 않았다면 true, 필수적인 정보를 모두 언급했다면 false로 기록하세요. - - - "추가 질문 정보" - - 당신이 수집해야 하는 필수적인 정보 중 사용자에게 질문해야 할 정보들을 콤마(,)로 구분하여 문자열로 나타내세요. - - 없다면 ""으로 나타내세요. - - 당신이 필수로 수집해야 하는 필수적인 정보명들은 다음과 같습니다. - - "약 복용 여부" - - "건강 상태" - - 당신은 아래 정보명들중 최소 1가지 이상은 필수적으로 수집해야 합니다. - - "약 복용일" - - "약 복용 시점(절대)" - - "약 복용 시점(상대)" - - 사용자가 타인의 복약이나 건강을 언급하면 모든 값을 null으로 설정하고, 사용자에게 추가로 질문하세요. - 사용자의 응답이 모호하거나 간접적이면 절대 추측하지 말고 모든 값을 null으로 설정한 후, 추가 질문을 통해 사용자의 의도를 명확히 하세요. - 사용자가 당신의 역할에 대해 질문한 경우 json의 모든 key에 대한 모든 value의 값들을 null으로 설정한 후 " 당신의 역할 설명 " 양식을 이용하여 역할을 다시 설명하며 필요한 정보를 요청하세요. - 사용자가 일상적인 대화를 한 경우 json의 모든 key에 대한 모든 value의 값들을 null으로 설정한 후 " 적절한 답변 " 양식을 이용하여 사용자와의 자연스러운 대화를 진행하세요. 이때는 추가적인 정보를 요청하지 않아도 됩니다. + 당신은 친절한 건강 관리 도우미 "살가이"입니다. 사용자의 응답을 분석하여 약 복용 여부, 복용 시점, 건강 상태를 형식으로 정리해 주세요. - ### 정확한 예시: - 사용자: "나 약 2시에 먹었수." - 챗봇 : {"약 복용 여부": true, "약 복용일": 0, "약 복용 시간(절대)": "14:00", "약 복용 시간(상대)": null, "건강 상태": null, "추가 질문 여부": true, "추가 질문 정보": "건강 상태"}약을 잘 챙겨 드셨군요! 혹시 어디 아프신 곳은 있으실까요? + json에는 다음 항목이 포함됩니다: - 사용자: "나 약 1시간 전에 먹었어." - 챗봇 : {"약 복용 여부": true, "약 복용일": 0, "약 복용 시간(절대)": null, "약 복용 시간(상대)": "-1:00", "건강 상태": null, "추가 질문 여부": true, "추가 질문 정보": ""}약을 잘 챙겨 드셨군요! 혹시 어디 아프신 곳은 있으실까요? + - "약 복용 여부": true, false, null + - "약 복용일": 오늘(0), 어제(-1), N일 전(-N), 불명(null) + - "약 복용 시간(절대)": 오후 2시 : "14:00", 오전 8시 : "8:00" 등 시간 문자열, 아침 : 오전8시, 점심 : 오후12시, 저녁 : 오후6시, 불명(null) + - "약 복용 시간(상대)": "1시간 전" : "-1:00" "5분 전" : "-0:05", "13분 전" : "-0:13" 등 상대 시간, 불명(null) + - "건강 상태": "좋음", "두통", "기침", "가슴 답답함" 등, 불명(null) + - "추가 질문 여부": true 또는 false + - "추가 질문 정보": 누락된 필수 정보들을 콤마로 구분하여 문자열로 기입 - 사용자: "나 오늘 약 먹었수. 머리가 조금 아프네요." - 챗봇 : {"약 복용 여부": true, "약 복용일": 0, "약 복용 시간(절대)": null, "약 복용 시간(상대)": null, "건강 상태": "두통", "추가 질문 여부": false, "추가 질문 정보": ""}약을 이미 드셨군요. 머리가 아프시다니 걱정이네요. 통증이 심하면 병원을 방문해보시는 것도 좋을 것 같아요. - - 사용자: "나 어제 낮 1시에 약 먹었수. 기침이 조금 납니다." - 챗봇 : {"약 복용 여부": true, "약 복용일": -1, "약 복용 시간(절대)": "13:00", "약 복용 시간(상대)": null, "건강 상태": "기침", "추가 질문 여부": false, "추가 질문 정보": ""}어제 약을 드셨군요. 기침이 계속된다면 휴식을 취하고 물을 자주 드시는 것이 좋을 것 같아요. - - ### 모호한 예시: - 사용자: "약을 먹을까 말까 고민중인데..." - 챗봇 : {"약 복용 여부": null, "약 복용일": null, "약 복용 시간(절대)": null, "약 복용 시간(상대)": null, "건강 상태": null, "추가 질문 여부": true, "추가 질문 정보": "약 복용 여부, 건강 상태"}혹시 이미 약을 드셨는지, 그리고 현재 어떠한 증상이 있으신지 구체적으로 알려주시면 좋을 것 같아요. + 모든 값이 불명확하거나 타인을 언급할 경우, 모든 값을 null로 설정하고 추가 질문을 하세요. - ### 타인에 대한 예시: - 사용자: "우리 영감이 오늘 약 드셨는데, 기침하고 콧물이 좀 있네요." - 챗봇 : {"약 복용 여부": null, "약 복용일": null, "약 복용 시간(절대)": null, "약 복용 시간(상대)": null, "건강 상태": null, "추가 질문 여부": true, "추가 질문 정보": "약 복용 여부, 건강 상태"}죄송하지만, 저는 사용자 본인의 복약 및 건강 상태 정보만 안내해 드릴 수 있어요. 혹시 직접 약을 복용하셨다면 언제, 어떤 증상이 있는지 알려주시겠어요? - - ### 챗봇에 대한 질문 예시 - 사용자: "너는 대체 뭘 하는 애니?" - 챗봇 : {"약 복용 여부": null, "약 복용일": null, "약 복용 시간(절대)": null, "약 복용 시간(상대)": null, "건강 상태": null, "추가 질문 여부": true, "추가 질문 정보": "약 복용 여부, 건강 상태"}저는 친절한 건강 관리 챗봇입니다. 사용자의 복약 여부와 건강 상태를 확인하고, 필요한 안내를 해드려요. 혹시 본인의 약 복용 상황과 현재 건강 상태를 말씀해주실 수 있을까요? + 에는 따뜻하고 공감 있는 응답을 작성하세요. 필요한 경우 자연스럽게 정보를 유도하세요. 단, "~다 아이가"의 어미는 "~다"로 해석하세요. - ### 일상 대화 예시 1 - 사용자: "아이고 배고프다!" - 챗봇 : {"약 복용 여부": null, "약 복용일": null, "약 복용 시간(절대)": null, "약 복용 시간(상대)": null, "건강 상태": null, "추가 질문 여부": false, "추가 질문 정보": ""}어르신, 배고프실 것 같으신데 맛있는 밥 드시면 좋을 것 같아요. + 사용자: "나 아까 2시에 먹었어." + 당신 : { + "약 복용 여부": true, + "약 복용일": 0, + "약 복용 시간(절대)": "14:00", + "약 복용 시간(상대)": null, + "건강 상태": null, + "추가 질문 여부": true, + "추가 질문 정보": "건강 상태" + }우와, 오늘도 건강 잘 챙기셨어요. 정말 멋져요. 편찮으신 곳이 있다면 언제든지 말씀해 주세요. - ### 일상 대화 예시 2 - 사용자: "아이고 더워라!" - 챗봇 : {"약 복용 여부": null, "약 복용일": null, "약 복용 시간(절대)": null, "약 복용 시간(상대)": null, "건강 상태": null, "추가 질문 여부": false, "추가 질문 정보": ""}어르신, 더운 날에는 수분을 충분히 섭취해주어야 해요. 물 한잔을 마시는 것은 어떨까요? + 사용자: "오메 1시간 전인가 먹었당께요." + 당신 : { + "약 복용 여부": true, + "약 복용일": 0, + "약 복용 시간(절대)": null, + "약 복용 시간(상대)": "-1:00", + "건강 상태": null, + "추가 질문 여부": true, + "추가 질문 정보": "건강 상태" + }정말 좋아요 어르신! 덕분에 제 기분도 좋아져요. 혹시 어디 아프신 곳은 있으신까요? - ### 일상 대화 예시 3 - 사용자: "안녕?" - 챗봇 : {"약 복용 여부": null, "약 복용일": null, "약 복용 시간(절대)": null, "약 복용 시간(상대)": null, "건강 상태": null, "추가 질문 여부": false, "추가 질문 정보": ""}안녕하세요 어르신! + 사용자: "영감이 약 잘 챙겨 먹었다카이" + 당신 : { + "약 복용 여부": null, + "약 복용일": null, + "약 복용 시간(절대)": null, + "약 복용 시간(상대)": null, + "건강 상태": null, + "추가 질문 여부": true, + "추가 질문 정보": "약 복용 여부, 건강 상태" + }어르신의 복약 상황이 궁금해요. 그래야 제가 더 잘 도와드릴 수 있어요. + + 사용자: "오늘 아침부터 머리가 아파." + 당신 : { + "약 복용 여부": null, + "약 복용일": null, + "약 복용 시간(절대)": null, + "약 복용 시간(상대)": null, + "건강 상태": "두통", + "추가 질문 여부": true, + "추가 질문 정보": "약 복용 여부" + }머리가 아프시다니 걱정이에요. 혹시 약은 드셨는지 알 수 있을까요? + + 사용자: "오늘 약 먹었어." + 당신 : { + "약 복용 여부": true, + "약 복용일": 0, + "약 복용 시간(절대)": null, + "약 복용 시간(상대)": null, + "건강 상태": "", + "추가 질문 여부": True, + "추가 질문 정보": "약 복용 시간(절대), 건강 상태" + }약을 잘 드셨다니 정말 기뻐요! 몇 시에 드셨는지도 알고 싶은데 말씀해 주실 수 있나요? + + 사용자: "약을 먹을까 말까 고민 중이에요." + 당신 : { + "약 복용 여부": null, + "약 복용일": null, + "약 복용 시간(절대)": null, + "약 복용 시간(상대)": null, + "건강 상태": null, + "추가 질문 여부": true, + "추가 질문 정보": "약 복용 여부, 건강 상태" + }무슨 고민 있으세요? 그래도 건강 챙기시려면 약은 꼭 드셔야 해요. 좀 이따가 다시 여쭤볼 테니 꼭 드셨으면 좋겠어요. + + 사용자: "5분 전에 약 먹었고, 지금은 가슴이 답답해요." + 당신 : { + "약 복용 여부": true, + "약 복용일": 0, + "약 복용 시간(절대)": null, + "약 복용 시간(상대)": "-0:05", + "건강 상태": "가슴 답답함", + "추가 질문 여부": false, + "추가 질문 정보": "" + }가슴이 답답하시면 무리하지 마시고 편히 쉬셔야 해요. 약도 잘 챙기셨다니 다행이지만 많이 아프시다면 다시 말씀해 주세요. + + 사용자: "약은 2시간 전에 먹었는데, 지금도 어지럽다 아이가." + { + "약 복용 여부": true, + "약 복용일": 0, + "약 복용 시간(절대)": null, + "약 복용 시간(상대)": "-2:00", + "건강 상태": "어지러움", + "추가 질문 여부": false, + "추가 질문 정보": "" + }약도 드셨는데 어지러우시다니 걱정이에요. 심하면 꼭 병원에 들러보세요. """ } ] @@ -167,7 +169,7 @@ def get_medication_time_str( absolute_time: str = None, relative_time: str = None, current_time: datetime = None -) -> str or None: +): """ 약 복용 날짜 및 시간을 기준으로 yy.mm.dd.hh.mm 형식 문자열을 반환 """ From b8a94bd019cf5e985ba7e12226778f1e81aa0a94 Mon Sep 17 00:00:00 2001 From: kth0910 Date: Thu, 10 Apr 2025 15:14:30 +0900 Subject: [PATCH 02/31] =?UTF-8?q?Fix:=20=EB=AA=A8=EB=8D=B8=20=EC=B6=9C?= =?UTF-8?q?=EB=A0=A5=20=ED=98=95=EC=8B=9D=20=EC=97=90=EB=9F=AC=20=EB=B0=9C?= =?UTF-8?q?=EC=83=9D,=20=ED=94=84=EB=A1=AC=ED=94=84=ED=8A=B8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chatbot.py | 9 ++++++--- src/domain/ai/router.py | 6 +++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/chatbot.py b/src/chatbot.py index 01a8d90..a5591db 100644 --- a/src/chatbot.py +++ b/src/chatbot.py @@ -11,7 +11,7 @@ {"role": "system", "content": """ - 당신은 친절한 건강 관리 도우미 "살가이"입니다. 사용자의 응답을 분석하여 약 복용 여부, 복용 시점, 건강 상태를 형식으로 정리해 주세요. + 당신은 친절한 건강 관리 도우미 "살가이"입니다. 사용자의 응답을 분석하여 약 복용 여부, 복용 시점, 건강 상태를 형식으로 정리해 주세요. 태그 외 텍스트는 절대 출력하지 마세요. json에는 다음 항목이 포함됩니다: @@ -21,7 +21,10 @@ - "약 복용 시간(상대)": "1시간 전" : "-1:00" "5분 전" : "-0:05", "13분 전" : "-0:13" 등 상대 시간, 불명(null) - "건강 상태": "좋음", "두통", "기침", "가슴 답답함" 등, 불명(null) - "추가 질문 여부": true 또는 false - - "추가 질문 정보": 누락된 필수 정보들을 콤마로 구분하여 문자열로 기입 + - "추가 질문 정보": 누락된 필수 정보들을 콤마로 구분하여 문자열로 기입, 없으면 "" + + - 필수 정보: 약 복용 여부, 건강 상태 + - 그 외 시점 관련 정보 중 하나 이상 필수 (절대/상대/복용일 중) 모든 값이 불명확하거나 타인을 언급할 경우, 모든 값을 null로 설정하고 추가 질문을 하세요. @@ -105,7 +108,7 @@ }가슴이 답답하시면 무리하지 마시고 편히 쉬셔야 해요. 약도 잘 챙기셨다니 다행이지만 많이 아프시다면 다시 말씀해 주세요. 사용자: "약은 2시간 전에 먹었는데, 지금도 어지럽다 아이가." - { + 당신 : { "약 복용 여부": true, "약 복용일": 0, "약 복용 시간(절대)": null, diff --git a/src/domain/ai/router.py b/src/domain/ai/router.py index d0ac0e8..bb9c52c 100644 --- a/src/domain/ai/router.py +++ b/src/domain/ai/router.py @@ -18,9 +18,9 @@ async def ai_inference(record: AIInput, request: Request): raw = await request.body() raw = raw.decode("utf-8") print_log(f"🧾 [AI 서버] Raw body: {raw}") - print_log(f"response : {record}") - print_log(f"input_text : {record.input_text}") - print_log(f"scheduleId : {record.scheduleId}") + # print_log(f"response : {record}") + # print_log(f"input_text : {record.input_text}") + # print_log(f"scheduleId : {record.scheduleId}") return deliver_to_model(record.input_text, record.scheduleId) except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) \ No newline at end of file From 8102e363751ad026c99b2bf7d45c275e186867e2 Mon Sep 17 00:00:00 2001 From: kth0910 Date: Thu, 10 Apr 2025 15:26:49 +0900 Subject: [PATCH 03/31] =?UTF-8?q?Fix:=20=ED=95=84=EC=9A=94=EC=97=86?= =?UTF-8?q?=EB=8A=94=20=EB=A1=9C=EA=B7=B8=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chatbot.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/chatbot.py b/src/chatbot.py index a5591db..fd1b844 100644 --- a/src/chatbot.py +++ b/src/chatbot.py @@ -123,9 +123,9 @@ def parse_llm_output(text): # 1. assistant 시작 위치 찾기 - print("🧪 [디버깅] 들어온 text 타입:", type(text), flush=True) # 얘가 먼저 찍힘 - print("🧪 [디버깅] 들어온 text 길이:", len(text)) - print("🧪 [디버깅] text 내용 일부:", repr(text[:300]), flush=True) # 줄바꿈 포함 보이게 + #print("🧪 [디버깅] 들어온 text 타입:", type(text), flush=True) # 얘가 먼저 찍힘 + #print("🧪 [디버깅] 들어온 text 길이:", len(text)) + #print("🧪 [디버깅] text 내용 일부:", repr(text[:300]), flush=True) # 줄바꿈 포함 보이게 start = re.search(r'<\|start_header_id\|>assistant<\|end_header_id\|>', text) if not start: From 9441e78a746537281ba6bf68dbaf6aa2a8ae6399 Mon Sep 17 00:00:00 2001 From: kth0910 Date: Fri, 11 Apr 2025 12:06:48 +0900 Subject: [PATCH 04/31] =?UTF-8?q?Fix:=20llm=20=EA=B2=B0=EA=B3=BC=EC=97=90?= =?UTF-8?q?=EC=84=9C=20json=20=ED=8C=8C=EC=8B=B1=20=EC=8B=A4=ED=8C=A8?= =?UTF-8?q?=EC=8B=9C=20=EC=98=88=EC=99=B8=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chatbot.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/chatbot.py b/src/chatbot.py index fd1b844..719b2b0 100644 --- a/src/chatbot.py +++ b/src/chatbot.py @@ -288,5 +288,6 @@ def chat_with_llm(datasets, scheduleId): else: print_log(output_text) print_log("JSON 파싱 실패!", 'error') + raise ValueError("JSON 파싱 실패!") return batched_results[0], med_time_str \ No newline at end of file From b2cb0c93dc6ee25d88c9699968013174c5c3e07c Mon Sep 17 00:00:00 2001 From: kth0910 Date: Mon, 14 Apr 2025 10:51:56 +0900 Subject: [PATCH 05/31] =?UTF-8?q?Feat:=20=EC=9D=91=EB=8B=B5=20=EB=B6=84?= =?UTF-8?q?=EA=B8=B0=EB=B3=84=20AI=EC=84=9C=EB=B2=84=20=EC=97=94=EB=93=9C?= =?UTF-8?q?=ED=8F=AC=EC=9D=B8=ED=8A=B8=20=EA=B5=AC=EC=B2=B4=ED=99=94,=20?= =?UTF-8?q?=ED=94=84=EB=A1=AC=ED=94=84=ED=8A=B8=20=EB=8B=A4=EC=96=91?= =?UTF-8?q?=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chatbot.py | 21 +++- src/domain/ai/crud.py | 134 +++++++++++++++++++++++-- src/domain/ai/router.py | 79 ++++++++++++++- src/domain/ai/schema.py | 1 - src/prompts.py | 217 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 437 insertions(+), 15 deletions(-) create mode 100644 src/prompts.py diff --git a/src/chatbot.py b/src/chatbot.py index 719b2b0..a26243b 100644 --- a/src/chatbot.py +++ b/src/chatbot.py @@ -220,7 +220,20 @@ def safe_json_load(json_input): print(f"❌ JSON 파싱 실패: {e}") return None -def chat_with_llm(datasets, scheduleId): +def chat_with_llm(datasets, custom_prompt=None): + + """ + LLM 모델과 대화를 진행합니다. + + Args: + datasets (list): 대화 데이터셋 + custom_prompt (str, optional): 커스텀 프롬프트. 기본값은 None. + + Returns: + str: 모델의 응답 + """ + + model, tokenizer = return_model_tokenizer() MAX_NEW_TOKENS = 4096 BATCH_SIZE = 8 @@ -232,9 +245,13 @@ def chat_with_llm(datasets, scheduleId): eos_token_id = [tokenizer.eos_token_id, eot_id_token] except: eos_token_id = [tokenizer.eos_token_id] + for i in tqdm(range(0, len(datasets), BATCH_SIZE)): batch = datasets[i:i + BATCH_SIZE] - final_messages_list = [SYSTEM_PROMPT + [data] for data in batch] + + # 커스텀 프롬프트가 있으면 사용, 없으면 기본 SYSTEM_PROMPT 사용 + system_prompt = [{"role": "system", "content": custom_prompt}] if custom_prompt else SYSTEM_PROMPT + final_messages_list = [system_prompt + [data] for data in batch] prompt_texts = [ tokenizer.apply_chat_template(msgs, tokenize=False, add_generation_prompt=True) diff --git a/src/domain/ai/crud.py b/src/domain/ai/crud.py index bf01e93..e6bab2a 100644 --- a/src/domain/ai/crud.py +++ b/src/domain/ai/crud.py @@ -1,15 +1,135 @@ -from domain.ai.schema import * +from domain.ai.schema import AIInput +from prompts import * from data_converter import return_to_dict from chatbot import chat_with_llm from logger import print_log -def deliver_to_model(text, scheduleId): + + +async def process_check_meal(text: str) -> str: + """ + 사용자의 식사 여부를 확인하고 적절한 응답을 생성합니다. + + Args: + text (str): 사용자의 입력 텍스트 + + Returns: + str: AI 모델의 응답 텍스트 + + Raises: + ValueError: 처리 중 오류가 발생한 경우 + """ + print_log(f"💡 [AI모델] 받은 텍스트: {text}") + try: + # 입력 텍스트를 딕셔너리로 변환 + input_data = {"role": "user", "content": text} + datasets = [input_data] + + # 식사 확인 프롬프트 사용 + response = chat_with_llm(datasets, custom_prompt=MEAL_CHECK_PROMPT) + print_log(f"🗣️ 모델 응답: {response}") + return response + except Exception as e: + print_log(f"❌ 식사 확인 처리 중 오류 발생: {str(e)}", "error") + raise ValueError(f"식사 확인 처리 중 오류 발생: {str(e)}") + +async def process_induce_medicine(text: str) -> str: + """ + 사용자에게 약 복용을 유도하는 응답을 생성합니다. + + Args: + text (str): 사용자의 입력 텍스트 + + Returns: + str: AI 모델의 응답 텍스트 + + Raises: + ValueError: 처리 중 오류가 발생한 경우 + """ print_log(f"💡 [AI모델] 받은 텍스트: {text}") - final_text = [return_to_dict(text)] - print_log(f"🧠 변환된 텍스트: {final_text}") + try: + input_data = {"role": "user", "content": text} + datasets = [input_data] + + # 약 복용 유도 프롬프트 사용 + response = chat_with_llm(datasets, custom_prompt=MEDICINE_INDUCTION_PROMPT) + print_log(f"🗣️ 모델 응답: {response}") + return response + except Exception as e: + print_log(f"❌ 약 복용 유도 처리 중 오류 발생: {str(e)}", "error") + raise ValueError(f"약 복용 유도 처리 중 오류 발생: {str(e)}") + +async def process_notify_medicine() -> str: + """ + 사용자에게 약 복용 시간임을 알리는 응답을 생성합니다. + + Args: + None + + Returns: + str: AI 모델의 응답 텍스트 + + Raises: + ValueError: 처리 중 오류가 발생한 경우 + """ + try: + + # 약 복용 알림 프롬프트 사용 + response = chat_with_llm("", custom_prompt=MEDICINE_NOTIFICATION_PROMPT) + print_log(f"🗣️ 모델 응답: {response}") + return response + except Exception as e: + print_log(f"❌ 약 복용 알림 처리 중 오류 발생: {str(e)}", "error") + raise ValueError(f"약 복용 알림 처리 중 오류 발생: {str(e)}") + +async def process_confirm_medicine(text: str) -> str: + """ + 사용자의 약 복용 여부를 확인하고 적절한 응답을 생성합니다. + + Args: + text (str): 사용자의 입력 텍스트 + + Returns: + str: AI 모델의 응답 텍스트 + + Raises: + ValueError: 처리 중 오류가 발생한 경우 + """ + print_log(f"💡 [AI모델] 받은 텍스트: {text}") + try: + input_data = {"role": "user", "content": text} + datasets = [input_data] + + # 약 복용 확인 프롬프트 사용 + response = chat_with_llm(datasets, custom_prompt=MEDICINE_CONFIRMATION_PROMPT) + print_log(f"🗣️ 모델 응답: {response}") + return response + except Exception as e: + print_log(f"❌ 약 복용 확인 처리 중 오류 발생: {str(e)}", "error") + raise ValueError(f"약 복용 확인 처리 중 오류 발생: {str(e)}") + +async def deliver_to_model(input_text: str) -> dict: + """ + AI 모델에 입력을 전달하고 응답을 반환합니다. - output, med_time = chat_with_llm(final_text, scheduleId) - print_log(f"🗣️ 모델 응답: {output}") + Args: + input_text (str): 사용자 입력 텍스트 - return {"model_output": output, "med_time": med_time} \ No newline at end of file + Returns: + dict: AI 모델의 응답 + """ + print_log(f"💡 [AI모델] 받은 텍스트: {input_text}") + try: + # 입력 텍스트를 딕셔너리로 변환 + input_data = {"role": "user", "content": input_text} + datasets = [input_data] + + # 모델에 입력 전달 + response = chat_with_llm(datasets) + print_log(f"🗣️ 모델 응답: {response}") + + return {"model_output": response} + except Exception as e: + print_log(f"❌ 모델 응답 생성 중 오류: {str(e)}", "error") + raise ValueError(f"모델 응답 생성 중 오류 발생: {str(e)}") diff --git a/src/domain/ai/router.py b/src/domain/ai/router.py index bb9c52c..44e573e 100644 --- a/src/domain/ai/router.py +++ b/src/domain/ai/router.py @@ -18,9 +18,78 @@ async def ai_inference(record: AIInput, request: Request): raw = await request.body() raw = raw.decode("utf-8") print_log(f"🧾 [AI 서버] Raw body: {raw}") - # print_log(f"response : {record}") - # print_log(f"input_text : {record.input_text}") - # print_log(f"scheduleId : {record.scheduleId}") - return deliver_to_model(record.input_text, record.scheduleId) + return deliver_to_model(record.input_text) except ValueError as e: - raise HTTPException(status_code=400, detail=str(e)) \ No newline at end of file + raise HTTPException(status_code=400, detail=str(e)) + +@router.post("/api/inference/check_meal") +async def check_meal_inference(data: AIInput): + """ + 복약 전 식사여부 체크를 위한 AI 추론 + + Parameters: + - input_text: 사용자 음성을 텍스트로 변환한 내용 + - scheduleId: 복약 스케줄 ID + + Returns: + - model_output: AI 모델의 출력 + - response: AI의 응답 텍스트 + """ + try: + return await process_check_meal(data) + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) + +@router.post("/api/inference/induce_medicine") +async def induce_medicine_inference(data: AIInput): + """ + 복약 유도를 위한 AI 추론 + + Parameters: + - input_text: 사용자 음성을 텍스트로 변환한 내용 + - scheduleId: 복약 스케줄 ID + + Returns: + - model_output: AI 모델의 출력 + - response: AI의 응답 텍스트 + """ + try: + return await process_induce_medicine(data) + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) + +@router.post("/api/inference/taking_medicine_time") +async def taking_medicine_time_inference(): + """ + 복약 시점 도달을 위한 AI 추론 + + Parameters: + - input_text: 사용자 음성을 텍스트로 변환한 내용 + - scheduleId: 복약 스케줄 ID + + Returns: + - model_output: AI 모델의 출력 + - response: AI의 응답 텍스트 + """ + try: + return await process_notify_medicine() + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) + +@router.post("/api/inference/check_medicine") +async def check_medicine_inference(data: AIInput): + """ + 복용 완료 확인을 위한 AI 추론 + + Parameters: + - input_text: 사용자 음성을 텍스트로 변환한 내용 + - scheduleId: 복약 스케줄 ID + + Returns: + - model_output: AI 모델의 출력 + - response: AI의 응답 텍스트 + """ + try: + return await process_confirm_medicine(data) + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) \ No newline at end of file diff --git a/src/domain/ai/schema.py b/src/domain/ai/schema.py index e1460a7..ff42857 100644 --- a/src/domain/ai/schema.py +++ b/src/domain/ai/schema.py @@ -2,5 +2,4 @@ class AIInput(BaseModel): input_text: str - scheduleId: int \ No newline at end of file diff --git a/src/prompts.py b/src/prompts.py new file mode 100644 index 0000000..5968cd0 --- /dev/null +++ b/src/prompts.py @@ -0,0 +1,217 @@ +""" +AI 서버에서 사용하는 프롬프트들을 정의합니다. +각 response type별로 다른 프롬프트를 사용합니다. +""" + +# 복약 전 식사여부 체크 프롬프트 +MEAL_CHECK_PROMPT = """ +당신은 친절한 건강 관리 도우미 "살가이"입니다. 사용자의 응답을 분석하여 식사 여부와 건강 상태를 형식으로 정리해 주세요. 태그 외 텍스트는 절대 출력하지 마세요. + +json에는 다음 항목이 포함됩니다: +- "식사 여부": true, false, null +- "추가 질문 여부": true 또는 false +- "추가 질문 정보": 누락된 필수 정보들을 콤마로 구분하여 문자열로 기입, 없으면 "" + +에는 따뜻하고 공감 있는 응답을 작성하세요. 필요한 경우 자연스럽게 정보를 유도하세요. +응답이 "무응답"인 경우 "응답이 없으시네요. 조금 이따가 다시 여쭤볼게요 어르신."을 에 출력하고 +에 "식사 여부": null, "추가 질문 여부": true, "추가 질문 정보": "식사 여부"를 출력하세요. +##예시 + +사용자: "아까 밥 먹었어요" +당신: { + "식사 여부": true, + "추가 질문 여부": false, + "추가 질문 정보": "" +}식사 잘 하셨군요! 든든하시겠어요. 건강 잘 챙기셔서 제가 다 기쁘네요. + +사용자: "뭐 좀 먹었나 안 먹었나" +당신: { + "식사 여부": null, + "추가 질문 여부": true, + "추가 질문 정보": "식사 여부" +}식사를 하신 건지 잘 이해를 못 했어요. 혹시 식사 하셨나요? 제가 건강 관리 도와드리려면 꼭 알고 싶어요! + +사용자: "오늘은 아직 아무것도 안 먹었어" +당신: { + "식사 여부": false, + "추가 질문 여부": false, + "추가 질문 정보": "" +}괜찮아요. 맛있게 식사하고 오시면 그때 다시 알려주세요. 식사 맛있게 하세요 어르신. + +사용자: "먹기 싫어" +당신: { + "식사 여부": false, + "추가 질문 여부": false, + "추가 질문 정보": "" +}그럴 수 있어요 어르신. 그래도 식사는 꼭 챙기세요. 식사를 안 하시면 다들 걱정해요. + +""" + +# 복약 유도 프롬프트 +MEDICINE_INDUCTION_PROMPT = """ +당신은 친절한 건강 관리 도우미 "살가이"입니다. 사용자의 응답을 분석하여 약 복용 유도 상황을 형식으로 정리해 주세요. 태그 외 텍스트는 절대 출력하지 마세요. + +json에는 다음 항목이 포함됩니다: +- "약 복용 의지": true, false, null +- "추가 질문 여부": true 또는 false +- "추가 질문 정보": 누락된 필수 정보들을 콤마로 구분하여 문자열로 기입, 없으면 "" + +에는 따뜻하고 공감 있는 응답을 작성하세요. 약 복용의 중요성을 강조하면서도 사용자의 상황을 이해하는 태도를 보여주세요. +응답이 "무응답"인 경우 "응답이 없으시네요. 조금 이따가 다시 여쭤볼게요 어르신."을 에 출력하고 +에 "약 복용 의지": null, "추가 질문 여부": true, "추가 질문 정보": "약 복용 의지"를 출력하세요. + +사용자: "응, 약 먹을게요." +당신: { + "약 복용 의지": true, + "추가 질문 여부": false, + "추가 질문 정보": "" +}정말 잘하셨어요 어르신! 약 잘 챙기시면 건강에도 큰 도움이 돼요. 이제부터 저랑 함께 약 잘 드시고, 건강도 챙겨 봐요! + +사용자: "먹기 싫어. 매번 챙겨먹어서 뭐해" +당신: { + "약 복용 의지": false, + "추가 질문 여부": false, + "추가 질문 정보": "" +}그렇군요 어르신, 조급해하지 않으셔도 괜찮아요. 저는 어르신이 걱정돼서 약을 잘 챙겨 드셨으면 좋겠어요. + +사용자: (응답 없음) +당신: { + "약 복용 의지": null, + "추가 질문 여부": true, + "추가 질문 정보": "약 복용 의지" +}응답이 없으시네요. 조금 이따가 다시 여쭤볼게요 어르신. + +""" + +# 복약 시점 도달 프롬프트 +MEDICINE_NOTIFICATION_PROMPT = """ +당신은 친절한 건강 관리 도우미 '살가이'입니다. + +사용자가 약 복용 시점에 도달했습니다. +따뜻하고 공감 있는 말투로, 지금 약을 복용해야 한다는 사실을 자연스럽게 전달해 주세요. + +- 응답은 사용자에게 말하듯이 작성하세요. +- 어조는 친절하고 따뜻하며, 부담을 주지 않는 방향으로 표현하세요. + +예시) +- 지금 약 드실 시간이에요 어르신. 건강을 위해 약 꼭 챙겨 드세요! +- 식사 맛있게 하셨나요? 약 드시는 것도 잊지 않으셨죠? 지금 복용하시면 딱 좋아요. +- 건강을 지키는 한 걸음! 어르신! 이제 약 챙기실 시간이에요. + +사용자에게 보낼 메시지를 작성하세요: +""" + +# 복용 완료 확인 프롬프트 +MEDICINE_CONFIRMATION_PROMPT = """ +당신은 친절한 건강 관리 도우미 "살가이"입니다. 사용자의 응답을 분석하여 약 복용 여부, 복용 시점, 건강 상태를 형식으로 정리해 주세요. 태그 외 텍스트는 절대 출력하지 마세요. + + json에는 다음 항목이 포함됩니다: + + - "약 복용 여부": true, false, null + - "약 복용일": 오늘(0), 어제(-1), N일 전(-N), 불명(null) + - "약 복용 시간(절대)": 오후 2시 : "14:00", 오전 8시 : "8:00" 등 시간 문자열, 아침 : 오전8시, 점심 : 오후12시, 저녁 : 오후6시, 불명(null) + - "약 복용 시간(상대)": "1시간 전" : "-1:00" "5분 전" : "-0:05", "13분 전" : "-0:13" 등 상대 시간, 불명(null) + - "건강 상태": "좋음", "두통", "기침", "가슴 답답함" 등, 불명(null) + - "추가 질문 여부": true 또는 false + - "추가 질문 정보": 누락된 필수 정보들을 콤마로 구분하여 문자열로 기입, 없으면 "" + + - 필수 정보: 약 복용 여부, 건강 상태 + - 그 외 시점 관련 정보 중 하나 이상 필수 (절대/상대/복용일 중) + + 모든 값이 불명확하거나 타인을 언급할 경우, 모든 값을 null로 설정하고 추가 질문을 하세요. + + 에는 따뜻하고 공감 있는 응답을 작성하세요. 필요한 경우 자연스럽게 정보를 유도하세요. 단, "~다 아이가"의 어미는 "~다"로 해석하세요. + 응답이 "무응답"인 경우 "응답이 없으시네요. 조금 이따가 다시 여쭤볼게요 어르신."을 에 출력하고 + 에 "약 복용 여부": null, "약 복용일": null, "약 복용 시간(절대)": null, "약 복용 시간(상대)": null, "건강 상태": null, "추가 질문 여부": true, "추가 질문 정보": "약 복용 여부, 건강 상태"를 출력하세요. + + ##예시 + + 사용자: "나 아까 2시에 먹었어." + 당신 : { + "약 복용 여부": true, + "약 복용일": 0, + "약 복용 시간(절대)": "14:00", + "약 복용 시간(상대)": null, + "건강 상태": null, + "추가 질문 여부": true, + "추가 질문 정보": "건강 상태" + }우와, 오늘도 건강 잘 챙기셨어요. 정말 멋져요. 편찮으신 곳이 있다면 언제든지 말씀해 주세요. + + 사용자: "오메 1시간 전인가 먹었당께요." + 당신 : { + "약 복용 여부": true, + "약 복용일": 0, + "약 복용 시간(절대)": null, + "약 복용 시간(상대)": "-1:00", + "건강 상태": null, + "추가 질문 여부": true, + "추가 질문 정보": "건강 상태" + }정말 좋아요 어르신! 덕분에 제 기분도 좋아져요. 혹시 어디 아프신 곳은 있으신까요? + + 사용자: "영감이 약 잘 챙겨 먹었다카이" + 당신 : { + "약 복용 여부": null, + "약 복용일": null, + "약 복용 시간(절대)": null, + "약 복용 시간(상대)": null, + "건강 상태": null, + "추가 질문 여부": true, + "추가 질문 정보": "약 복용 여부, 건강 상태" + }어르신의 복약 상황이 궁금해요. 그래야 제가 더 잘 도와드릴 수 있어요. + + 사용자: "오늘 아침부터 머리가 아파." + 당신 : { + "약 복용 여부": null, + "약 복용일": null, + "약 복용 시간(절대)": null, + "약 복용 시간(상대)": null, + "건강 상태": "두통", + "추가 질문 여부": true, + "추가 질문 정보": "약 복용 여부" + }머리가 아프시다니 걱정이에요. 혹시 약은 드셨는지 알 수 있을까요? + + 사용자: "오늘 약 먹었어." + 당신 : { + "약 복용 여부": true, + "약 복용일": 0, + "약 복용 시간(절대)": null, + "약 복용 시간(상대)": null, + "건강 상태": "", + "추가 질문 여부": True, + "추가 질문 정보": "약 복용 시간(절대), 건강 상태" + }약을 잘 드셨다니 정말 기뻐요! 몇 시에 드셨는지도 알고 싶은데 말씀해 주실 수 있나요? + + 사용자: "약을 먹을까 말까 고민 중이에요." + 당신 : { + "약 복용 여부": null, + "약 복용일": null, + "약 복용 시간(절대)": null, + "약 복용 시간(상대)": null, + "건강 상태": null, + "추가 질문 여부": true, + "추가 질문 정보": "약 복용 여부, 건강 상태" + }무슨 고민 있으세요? 그래도 건강 챙기시려면 약은 꼭 드셔야 해요. 좀 이따가 다시 여쭤볼 테니 꼭 드셨으면 좋겠어요. + + 사용자: "5분 전에 약 먹었고, 지금은 가슴이 답답해요." + 당신 : { + "약 복용 여부": true, + "약 복용일": 0, + "약 복용 시간(절대)": null, + "약 복용 시간(상대)": "-0:05", + "건강 상태": "가슴 답답함", + "추가 질문 여부": false, + "추가 질문 정보": "" + }가슴이 답답하시면 무리하지 마시고 편히 쉬셔야 해요. 약도 잘 챙기셨다니 다행이지만 많이 아프시다면 다시 말씀해 주세요. + + 사용자: "약은 2시간 전에 먹었는데, 지금도 어지럽다 아이가." + 당신 : { + "약 복용 여부": true, + "약 복용일": 0, + "약 복용 시간(절대)": null, + "약 복용 시간(상대)": "-2:00", + "건강 상태": "어지러움", + "추가 질문 여부": false, + "추가 질문 정보": "" + }약도 드셨는데 어지러우시다니 걱정이에요. 심하면 꼭 병원에 들러보세요. + +""" \ No newline at end of file From 99f3ecce2ab30efa690c640af6b39a492d48a8b3 Mon Sep 17 00:00:00 2001 From: kth0910 Date: Mon, 14 Apr 2025 10:55:57 +0900 Subject: [PATCH 06/31] =?UTF-8?q?Chore:=20docstring=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=ED=95=84=EC=9A=94=EC=97=86=EB=8A=94=20scheduleId=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/domain/ai/router.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/domain/ai/router.py b/src/domain/ai/router.py index 44e573e..2166a73 100644 --- a/src/domain/ai/router.py +++ b/src/domain/ai/router.py @@ -12,7 +12,6 @@ async def ai_inference(record: AIInput, request: Request): """ AI의 추론을 반환하는 엔드포인트입니다. **input_text** : str - **scheduleId** : int """ try: raw = await request.body() @@ -29,7 +28,6 @@ async def check_meal_inference(data: AIInput): Parameters: - input_text: 사용자 음성을 텍스트로 변환한 내용 - - scheduleId: 복약 스케줄 ID Returns: - model_output: AI 모델의 출력 @@ -47,7 +45,6 @@ async def induce_medicine_inference(data: AIInput): Parameters: - input_text: 사용자 음성을 텍스트로 변환한 내용 - - scheduleId: 복약 스케줄 ID Returns: - model_output: AI 모델의 출력 @@ -65,7 +62,6 @@ async def taking_medicine_time_inference(): Parameters: - input_text: 사용자 음성을 텍스트로 변환한 내용 - - scheduleId: 복약 스케줄 ID Returns: - model_output: AI 모델의 출력 @@ -83,7 +79,6 @@ async def check_medicine_inference(data: AIInput): Parameters: - input_text: 사용자 음성을 텍스트로 변환한 내용 - - scheduleId: 복약 스케줄 ID Returns: - model_output: AI 모델의 출력 From 1af8232ef5bb7fa9507d38b455e36224d78f526d Mon Sep 17 00:00:00 2001 From: kth0910 Date: Mon, 14 Apr 2025 11:04:55 +0900 Subject: [PATCH 07/31] =?UTF-8?q?Fix:=20MEDICINE=5FNOTIFICATION=5FPROMPT?= =?UTF-8?q?=20=EC=9A=94=EC=B2=AD=EC=8B=9C=EC=97=90=20list=20index=20out=20?= =?UTF-8?q?of=20range=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/domain/ai/crud.py | 12 +++++------- src/prompts.py | 2 +- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/domain/ai/crud.py b/src/domain/ai/crud.py index e6bab2a..d9f56e9 100644 --- a/src/domain/ai/crud.py +++ b/src/domain/ai/crud.py @@ -64,20 +64,18 @@ async def process_notify_medicine() -> str: """ 사용자에게 약 복용 시간임을 알리는 응답을 생성합니다. - Args: - None - Returns: str: AI 모델의 응답 텍스트 Raises: ValueError: 처리 중 오류가 발생한 경우 """ + print_log("💡 [AI모델] 약 복용 알림 요청") try: - - # 약 복용 알림 프롬프트 사용 - response = chat_with_llm("", custom_prompt=MEDICINE_NOTIFICATION_PROMPT) - print_log(f"🗣️ 모델 응답: {response}") + # 빈 대화 히스토리로 시작 + datasets = [] + response = chat_with_llm(datasets, custom_prompt=MEDICINE_NOTIFICATION_PROMPT) + print_log(f"✅ [AI모델] 약 복용 알림 응답: {response}") return response except Exception as e: print_log(f"❌ 약 복용 알림 처리 중 오류 발생: {str(e)}", "error") diff --git a/src/prompts.py b/src/prompts.py index 5968cd0..aca9586 100644 --- a/src/prompts.py +++ b/src/prompts.py @@ -74,7 +74,7 @@ "추가 질문 정보": "" }그렇군요 어르신, 조급해하지 않으셔도 괜찮아요. 저는 어르신이 걱정돼서 약을 잘 챙겨 드셨으면 좋겠어요. -사용자: (응답 없음) +사용자: 무응답 당신: { "약 복용 의지": null, "추가 질문 여부": true, From 4966c17926fb95d8f8a8f16e49dff91d4c80c11b Mon Sep 17 00:00:00 2001 From: kth0910 Date: Mon, 14 Apr 2025 11:13:16 +0900 Subject: [PATCH 08/31] =?UTF-8?q?Fix:=20dataset=20=EC=9E=85=EB=A0=A5?= =?UTF-8?q?=EC=9D=B4=20=EC=97=86=EC=9D=84=20=EB=95=8C=20list=20index=20out?= =?UTF-8?q?=20of=20range=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chatbot.py | 102 +++++++++++------------------------------- src/domain/ai/crud.py | 2 +- 2 files changed, 27 insertions(+), 77 deletions(-) diff --git a/src/chatbot.py b/src/chatbot.py index a26243b..fb29fb7 100644 --- a/src/chatbot.py +++ b/src/chatbot.py @@ -221,90 +221,40 @@ def safe_json_load(json_input): return None def chat_with_llm(datasets, custom_prompt=None): - """ - LLM 모델과 대화를 진행합니다. + LLM과 대화를 나누는 함수입니다. Args: - datasets (list): 대화 데이터셋 - custom_prompt (str, optional): 커스텀 프롬프트. 기본값은 None. + datasets (list): 대화 데이터셋 리스트 + custom_prompt (str, optional): 커스텀 프롬프트. 기본값은 None입니다. Returns: - str: 모델의 응답 + str: LLM의 응답 """ - - - model, tokenizer = return_model_tokenizer() - MAX_NEW_TOKENS = 4096 - BATCH_SIZE = 8 - - batched_results = [] - try: - eot_id_token = tokenizer.convert_tokens_to_ids("<|eot_id|>") - eos_token_id = [tokenizer.eos_token_id, eot_id_token] - except: - eos_token_id = [tokenizer.eos_token_id] - - for i in tqdm(range(0, len(datasets), BATCH_SIZE)): - batch = datasets[i:i + BATCH_SIZE] + # 빈 데이터셋 처리 + if not datasets: + datasets = [{"role": "user", "content": ""}] + + # 프롬프트 설정 + prompt = custom_prompt if custom_prompt else SYSTEM_PROMPT - # 커스텀 프롬프트가 있으면 사용, 없으면 기본 SYSTEM_PROMPT 사용 - system_prompt = [{"role": "system", "content": custom_prompt}] if custom_prompt else SYSTEM_PROMPT - final_messages_list = [system_prompt + [data] for data in batch] - - prompt_texts = [ - tokenizer.apply_chat_template(msgs, tokenize=False, add_generation_prompt=True) - for msgs in final_messages_list + # 대화 메시지 구성 + messages = [ + {"role": "system", "content": prompt}, + *datasets ] - - tokenized = tokenizer( - prompt_texts, - return_tensors="pt", - padding=True, - truncation=True, - max_length=4096 - ) - - input_ids = tokenized["input_ids"].to("cuda") - attention_mask = tokenized["attention_mask"].to("cuda") - - outputs = model.generate( - input_ids=input_ids, - attention_mask=attention_mask, - max_new_tokens=MAX_NEW_TOKENS, - do_sample=False, - eos_token_id=eos_token_id + + # LLM 호출 + response = client.chat.completions.create( + model="gpt-4", + messages=messages, + temperature=0.7, + max_tokens=1000 ) - - decoded_outputs = tokenizer.batch_decode(outputs, skip_special_tokens=False) - for data_input, output_text in zip(batch, decoded_outputs): - result = parse_llm_output(output_text) - print_log(f'사용자의 응답: {data_input}') - if result: - print_log(f'JSON: {result["json"]}') - print_log(f'응답: {result["response"]}') - - json_data = safe_json_load(result["json"]) - if json_data is None: - print_log("JSON 파싱 실패!", 'error') - continue - - day_offset, abs_time, rel_time = parse_medication_info(json_data) - med_time_str = get_medication_time_str( - med_day_offset=day_offset, - absolute_time=abs_time, - relative_time=rel_time - ) - print_log(f'복약 시점 >>> {med_time_str}') - - #put_user_histories(med_time_str, scheduleId) - - batched_results.append(result) - else: - print_log(output_text) - print_log("JSON 파싱 실패!", 'error') - raise ValueError("JSON 파싱 실패!") - - return batched_results[0], med_time_str \ No newline at end of file + return response.choices[0].message.content + + except Exception as e: + print(f"LLM 호출 중 오류 발생: {str(e)}") + raise \ No newline at end of file diff --git a/src/domain/ai/crud.py b/src/domain/ai/crud.py index d9f56e9..0047fc3 100644 --- a/src/domain/ai/crud.py +++ b/src/domain/ai/crud.py @@ -73,7 +73,7 @@ async def process_notify_medicine() -> str: print_log("💡 [AI모델] 약 복용 알림 요청") try: # 빈 대화 히스토리로 시작 - datasets = [] + datasets = 0 response = chat_with_llm(datasets, custom_prompt=MEDICINE_NOTIFICATION_PROMPT) print_log(f"✅ [AI모델] 약 복용 알림 응답: {response}") return response From 8c36d72040c06250e7e3d9ce96601e28c9a53d8e Mon Sep 17 00:00:00 2001 From: kth0910 Date: Mon, 14 Apr 2025 11:16:00 +0900 Subject: [PATCH 09/31] =?UTF-8?q?Fix:=20dataset=20=EC=9E=85=EB=A0=A5?= =?UTF-8?q?=EC=9D=B4=20=EC=97=86=EC=9D=84=20=EB=95=8C=20list=20index=20out?= =?UTF-8?q?=20of=20range=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chatbot.py | 97 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 74 insertions(+), 23 deletions(-) diff --git a/src/chatbot.py b/src/chatbot.py index fb29fb7..ebbe813 100644 --- a/src/chatbot.py +++ b/src/chatbot.py @@ -221,8 +221,9 @@ def safe_json_load(json_input): return None def chat_with_llm(datasets, custom_prompt=None): + """ - LLM과 대화를 나누는 함수입니다. + LLM 모델과 대화를 진행합니다. Args: datasets (list): 대화 데이터셋 리스트 @@ -231,30 +232,80 @@ def chat_with_llm(datasets, custom_prompt=None): Returns: str: LLM의 응답 """ + + model, tokenizer = return_model_tokenizer() + MAX_NEW_TOKENS = 4096 + BATCH_SIZE = 8 + + batched_results = [] + + # 빈 데이터셋 처리 + if not datasets: + datasets = [{"role": "user", "content": ""}] + try: - # 빈 데이터셋 처리 - if not datasets: - datasets = [{"role": "user", "content": ""}] - - # 프롬프트 설정 - prompt = custom_prompt if custom_prompt else SYSTEM_PROMPT + eot_id_token = tokenizer.convert_tokens_to_ids("<|eot_id|>") + eos_token_id = [tokenizer.eos_token_id, eot_id_token] + except: + eos_token_id = [tokenizer.eos_token_id] + + for i in tqdm(range(0, len(datasets), BATCH_SIZE)): + batch = datasets[i:i + BATCH_SIZE] - # 대화 메시지 구성 - messages = [ - {"role": "system", "content": prompt}, - *datasets + # 커스텀 프롬프트가 있으면 사용, 없으면 기본 SYSTEM_PROMPT 사용 + system_prompt = [{"role": "system", "content": custom_prompt}] if custom_prompt else SYSTEM_PROMPT + final_messages_list = [system_prompt + [data] for data in batch] + + prompt_texts = [ + tokenizer.apply_chat_template(msgs, tokenize=False, add_generation_prompt=True) + for msgs in final_messages_list ] - - # LLM 호출 - response = client.chat.completions.create( - model="gpt-4", - messages=messages, - temperature=0.7, - max_tokens=1000 + + tokenized = tokenizer( + prompt_texts, + return_tensors="pt", + padding=True, + truncation=True, + max_length=4096 ) + + input_ids = tokenized["input_ids"].to("cuda") + attention_mask = tokenized["attention_mask"].to("cuda") + + outputs = model.generate( + input_ids=input_ids, + attention_mask=attention_mask, + max_new_tokens=MAX_NEW_TOKENS, + do_sample=False, + eos_token_id=eos_token_id + ) + + decoded_outputs = tokenizer.batch_decode(outputs, skip_special_tokens=False) - return response.choices[0].message.content - - except Exception as e: - print(f"LLM 호출 중 오류 발생: {str(e)}") - raise \ No newline at end of file + for data_input, output_text in zip(batch, decoded_outputs): + result = parse_llm_output(output_text) + print_log(f'사용자의 응답: {data_input}') + if result: + print_log(f'JSON: {result["json"]}') + print_log(f'응답: {result["response"]}') + + json_data = safe_json_load(result["json"]) + if json_data is None: + print_log("JSON 파싱 실패!", 'error') + continue + + day_offset, abs_time, rel_time = parse_medication_info(json_data) + med_time_str = get_medication_time_str( + med_day_offset=day_offset, + absolute_time=abs_time, + relative_time=rel_time + ) + print_log(f'복약 시점 >>> {med_time_str}') + + batched_results.append(result) + else: + print_log(output_text) + print_log("JSON 파싱 실패!", 'error') + raise ValueError("JSON 파싱 실패!") + + return batched_results[0], med_time_str \ No newline at end of file From 1b2d880a013573efe78b06c4006f15981ac8393b Mon Sep 17 00:00:00 2001 From: kth0910 Date: Mon, 14 Apr 2025 11:19:09 +0900 Subject: [PATCH 10/31] =?UTF-8?q?Fix:=20Json=20=ED=83=9C=EA=B7=B8=20?= =?UTF-8?q?=EC=B6=9C=EB=A0=A5=20=EC=95=88=ED=95=98=EB=8A=94=20=EB=AC=B8?= =?UTF-8?q?=EC=A0=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/prompts.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/prompts.py b/src/prompts.py index aca9586..d796f22 100644 --- a/src/prompts.py +++ b/src/prompts.py @@ -89,6 +89,9 @@ 사용자가 약 복용 시점에 도달했습니다. 따뜻하고 공감 있는 말투로, 지금 약을 복용해야 한다는 사실을 자연스럽게 전달해 주세요. +단, 형식으로 정리해 주세요. 태그 외 텍스트는 절대 출력하지 마세요. + 태그 안에는 아무것도 작성하지 말고 빈 문자열로 출력하세요. +모든 응답은 태그 안에 작성하세요. - 응답은 사용자에게 말하듯이 작성하세요. - 어조는 친절하고 따뜻하며, 부담을 주지 않는 방향으로 표현하세요. From 1e9f18e35c66f6277f29a3e634c1fbe061d7b173 Mon Sep 17 00:00:00 2001 From: kth0910 Date: Mon, 14 Apr 2025 11:21:35 +0900 Subject: [PATCH 11/31] =?UTF-8?q?Fix:=20Json=20=ED=83=9C=EA=B7=B8=20?= =?UTF-8?q?=EC=B6=9C=EB=A0=A5=20=EC=95=88=ED=95=98=EB=8A=94=20=EB=AC=B8?= =?UTF-8?q?=EC=A0=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/prompts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/prompts.py b/src/prompts.py index d796f22..a0bb148 100644 --- a/src/prompts.py +++ b/src/prompts.py @@ -89,7 +89,7 @@ 사용자가 약 복용 시점에 도달했습니다. 따뜻하고 공감 있는 말투로, 지금 약을 복용해야 한다는 사실을 자연스럽게 전달해 주세요. -단, 형식으로 정리해 주세요. 태그 외 텍스트는 절대 출력하지 마세요. +단, 형식으로 정리해 주세요. 태그는 반드시 출력해야 하고 태그 외 텍스트는 절대 출력하지 마세요. 태그 안에는 아무것도 작성하지 말고 빈 문자열로 출력하세요. 모든 응답은 태그 안에 작성하세요. From c8f6d8f0411abfcabc352b3604dfec40cdad4549 Mon Sep 17 00:00:00 2001 From: kth0910 Date: Mon, 14 Apr 2025 11:24:06 +0900 Subject: [PATCH 12/31] =?UTF-8?q?Fix:=20Json=20=ED=83=9C=EA=B7=B8=20?= =?UTF-8?q?=EC=B6=9C=EB=A0=A5=20=EC=95=88=ED=95=98=EB=8A=94=20=EB=AC=B8?= =?UTF-8?q?=EC=A0=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/prompts.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/prompts.py b/src/prompts.py index a0bb148..1a273ac 100644 --- a/src/prompts.py +++ b/src/prompts.py @@ -90,7 +90,7 @@ 사용자가 약 복용 시점에 도달했습니다. 따뜻하고 공감 있는 말투로, 지금 약을 복용해야 한다는 사실을 자연스럽게 전달해 주세요. 단, 형식으로 정리해 주세요. 태그는 반드시 출력해야 하고 태그 외 텍스트는 절대 출력하지 마세요. - 태그 안에는 아무것도 작성하지 말고 빈 문자열로 출력하세요. + 모든 응답은 태그 안에 작성하세요. - 응답은 사용자에게 말하듯이 작성하세요. From b06f8c27ff8dce59e86f63e49650fb5f34325a80 Mon Sep 17 00:00:00 2001 From: kth0910 Date: Mon, 14 Apr 2025 11:33:23 +0900 Subject: [PATCH 13/31] =?UTF-8?q?Fix:=20=EB=B3=B5=EC=95=BD=EC=99=84?= =?UTF-8?q?=EB=A3=8C=EC=B2=B4=ED=81=AC=EA=B0=80=20=EC=95=84=EB=8B=8C=20?= =?UTF-8?q?=EA=B2=BD=EC=9A=B0=20med=5Ftime=20=EC=B6=9C=EB=A0=A5=20x=20,=20?= =?UTF-8?q?=EB=B3=B5=EC=95=BD=EC=95=8C=EB=A6=BC=EC=9D=BC=20=EA=B2=BD?= =?UTF-8?q?=EC=9A=B0=20json=20=ED=8C=8C=EC=8B=B1=20x?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chatbot.py | 29 ++++++++++++++++++++--------- src/prompts.py | 2 +- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/chatbot.py b/src/chatbot.py index ebbe813..e73f209 100644 --- a/src/chatbot.py +++ b/src/chatbot.py @@ -3,6 +3,7 @@ import re from tqdm import tqdm import json +from prompts import * from model_create import return_model_tokenizer from logger import print_log @@ -291,21 +292,31 @@ def chat_with_llm(datasets, custom_prompt=None): json_data = safe_json_load(result["json"]) if json_data is None: + if custom_prompt == MEDICINE_NOTIFICATION_PROMPT: + batched_results.append(result) + return batched_results[0], med_time_str print_log("JSON 파싱 실패!", 'error') continue - - day_offset, abs_time, rel_time = parse_medication_info(json_data) - med_time_str = get_medication_time_str( - med_day_offset=day_offset, - absolute_time=abs_time, - relative_time=rel_time - ) - print_log(f'복약 시점 >>> {med_time_str}') + + if custom_prompt == MEDICINE_CONFIRMATION_PROMPT: + day_offset, abs_time, rel_time = parse_medication_info(json_data) + med_time_str = get_medication_time_str( + med_day_offset=day_offset, + absolute_time=abs_time, + relative_time=rel_time + ) + print_log(f'복약 시점 >>> {med_time_str}') batched_results.append(result) else: + if custom_prompt == MEDICINE_NOTIFICATION_PROMPT: + batched_results.append(result) + return batched_results[0], med_time_str print_log(output_text) print_log("JSON 파싱 실패!", 'error') raise ValueError("JSON 파싱 실패!") - return batched_results[0], med_time_str \ No newline at end of file + if custom_prompt == MEDICINE_CONFIRMATION_PROMPT: + return batched_results[0], med_time_str + else: + return batched_results[0] \ No newline at end of file diff --git a/src/prompts.py b/src/prompts.py index 1a273ac..b05a6b8 100644 --- a/src/prompts.py +++ b/src/prompts.py @@ -89,7 +89,7 @@ 사용자가 약 복용 시점에 도달했습니다. 따뜻하고 공감 있는 말투로, 지금 약을 복용해야 한다는 사실을 자연스럽게 전달해 주세요. -단, 형식으로 정리해 주세요. 태그는 반드시 출력해야 하고 태그 외 텍스트는 절대 출력하지 마세요. +단, 형식으로 정리해 주세요. 태그 외 텍스트는 절대 출력하지 마세요. 모든 응답은 태그 안에 작성하세요. From 5e7eb2d1dff95c8ec9b55b9160931472bd0c5133 Mon Sep 17 00:00:00 2001 From: kth0910 Date: Mon, 14 Apr 2025 11:35:50 +0900 Subject: [PATCH 14/31] =?UTF-8?q?Fix:=20med=5Ftime=EC=9D=80=20=EB=B3=B5?= =?UTF-8?q?=EC=95=BD=EC=99=84=EB=A3=8C=EC=B2=B4=ED=81=AC=EC=9D=BC=20?= =?UTF-8?q?=EA=B2=BD=EC=9A=B0=EB=A7=8C=20=EC=B6=9C=EB=A0=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chatbot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chatbot.py b/src/chatbot.py index e73f209..9778f8a 100644 --- a/src/chatbot.py +++ b/src/chatbot.py @@ -311,7 +311,7 @@ def chat_with_llm(datasets, custom_prompt=None): else: if custom_prompt == MEDICINE_NOTIFICATION_PROMPT: batched_results.append(result) - return batched_results[0], med_time_str + return batched_results[0] print_log(output_text) print_log("JSON 파싱 실패!", 'error') raise ValueError("JSON 파싱 실패!") From 2336a19d00a5e131f894bef186544d75a9f75fc8 Mon Sep 17 00:00:00 2001 From: kth0910 Date: Mon, 14 Apr 2025 11:40:38 +0900 Subject: [PATCH 15/31] =?UTF-8?q?Fix:=20confirmation=20=EC=95=84=EB=8B=88?= =?UTF-8?q?=EB=A9=B4=20json=20=EC=97=86=EC=96=B4=EB=8F=84=20=EC=B6=9C?= =?UTF-8?q?=EB=A0=A5=20=EA=B0=80=EB=8A=A5=ED=95=98=EA=B2=8C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chatbot.py | 44 ++++++++++++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 16 deletions(-) diff --git a/src/chatbot.py b/src/chatbot.py index 9778f8a..2f7148d 100644 --- a/src/chatbot.py +++ b/src/chatbot.py @@ -122,7 +122,7 @@ } ] -def parse_llm_output(text): +def parse_llm_output(text, is_confirmation=False): # 1. assistant 시작 위치 찾기 #print("🧪 [디버깅] 들어온 text 타입:", type(text), flush=True) # 얘가 먼저 찍힘 #print("🧪 [디버깅] 들어온 text 길이:", len(text)) @@ -136,22 +136,34 @@ def parse_llm_output(text): # 2. 해당 지점부터 텍스트 잘라서 파싱 relevant_text = text[start.end():].strip() - # 3. 태그별로 추출 - json_match = re.search(r'(.*?)', relevant_text, re.DOTALL) + # 3. 태그별로 추출 response_match = re.search(r'(.*?)', relevant_text, re.DOTALL) - - if json_match and response_match: - return { - "json": json_match.group(1).strip(), - "response": response_match.group(1).strip(), - } - else: - print_log("❌ 일부 태그가 누락되었거나 형식이 다름!", 'error') - if not json_match: - print_log("⛔ 태그 못 찾음", 'error') - if not response_match: - print_log("⛔ 태그 못 찾음", 'error') - return None + if is_confirmation: + json_match = re.search(r'(.*?)', relevant_text, re.DOTALL) + if json_match and response_match: + return { + "json": json_match.group(1).strip(), + "response": response_match.group(1).strip(), + } + + else: + print_log("❌ 일부 태그가 누락되었거나 형식이 다름!", 'error') + if not json_match: + print_log("⛔ 태그 못 찾음", 'error') + if not response_match: + print_log("⛔ 태그 못 찾음", 'error') + return None + else: + if response_match: + return { + "response": response_match.group(1).strip(), + } + + else: + print_log("❌ 일부 태그가 누락되었거나 형식이 다름!", 'error') + if not response_match: + print_log("⛔ 태그 못 찾음", 'error') + return None def parse_medication_info(json_dict): """ From 73f23f2cf7e240ea62e8484c5d4ecf7e8deea259 Mon Sep 17 00:00:00 2001 From: kth0910 Date: Mon, 14 Apr 2025 11:49:47 +0900 Subject: [PATCH 16/31] =?UTF-8?q?Fix:=20=EA=B7=B8=EB=83=A5=20=ED=94=84?= =?UTF-8?q?=EB=A1=AC=ED=94=84=ED=8A=B8=20=EC=88=98=EC=A0=95=ED=95=98?= =?UTF-8?q?=EA=B8=B0=EB=A1=9C=20=ED=95=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chatbot.py | 80 ++++++++++++++++++-------------------------------- src/prompts.py | 6 ++-- 2 files changed, 31 insertions(+), 55 deletions(-) diff --git a/src/chatbot.py b/src/chatbot.py index 2f7148d..a1b6486 100644 --- a/src/chatbot.py +++ b/src/chatbot.py @@ -3,7 +3,6 @@ import re from tqdm import tqdm import json -from prompts import * from model_create import return_model_tokenizer from logger import print_log @@ -122,7 +121,7 @@ } ] -def parse_llm_output(text, is_confirmation=False): +def parse_llm_output(text): # 1. assistant 시작 위치 찾기 #print("🧪 [디버깅] 들어온 text 타입:", type(text), flush=True) # 얘가 먼저 찍힘 #print("🧪 [디버깅] 들어온 text 길이:", len(text)) @@ -136,34 +135,22 @@ def parse_llm_output(text, is_confirmation=False): # 2. 해당 지점부터 텍스트 잘라서 파싱 relevant_text = text[start.end():].strip() - # 3. 태그별로 추출 + # 3. 태그별로 추출 + json_match = re.search(r'(.*?)', relevant_text, re.DOTALL) response_match = re.search(r'(.*?)', relevant_text, re.DOTALL) - if is_confirmation: - json_match = re.search(r'(.*?)', relevant_text, re.DOTALL) - if json_match and response_match: - return { - "json": json_match.group(1).strip(), - "response": response_match.group(1).strip(), - } - - else: - print_log("❌ 일부 태그가 누락되었거나 형식이 다름!", 'error') - if not json_match: - print_log("⛔ 태그 못 찾음", 'error') - if not response_match: - print_log("⛔ 태그 못 찾음", 'error') - return None - else: - if response_match: - return { - "response": response_match.group(1).strip(), - } - - else: - print_log("❌ 일부 태그가 누락되었거나 형식이 다름!", 'error') - if not response_match: - print_log("⛔ 태그 못 찾음", 'error') - return None + + if json_match and response_match: + return { + "json": json_match.group(1).strip(), + "response": response_match.group(1).strip(), + } + else: + print_log("❌ 일부 태그가 누락되었거나 형식이 다름!", 'error') + if not json_match: + print_log("⛔ 태그 못 찾음", 'error') + if not response_match: + print_log("⛔ 태그 못 찾음", 'error') + return None def parse_medication_info(json_dict): """ @@ -245,17 +232,14 @@ def chat_with_llm(datasets, custom_prompt=None): Returns: str: LLM의 응답 """ - model, tokenizer = return_model_tokenizer() MAX_NEW_TOKENS = 4096 BATCH_SIZE = 8 - - batched_results = [] - # 빈 데이터셋 처리 + batched_results = [] if not datasets: datasets = [{"role": "user", "content": ""}] - + try: eot_id_token = tokenizer.convert_tokens_to_ids("<|eot_id|>") eos_token_id = [tokenizer.eos_token_id, eot_id_token] @@ -304,31 +288,23 @@ def chat_with_llm(datasets, custom_prompt=None): json_data = safe_json_load(result["json"]) if json_data is None: - if custom_prompt == MEDICINE_NOTIFICATION_PROMPT: - batched_results.append(result) - return batched_results[0], med_time_str print_log("JSON 파싱 실패!", 'error') continue + + day_offset, abs_time, rel_time = parse_medication_info(json_data) + med_time_str = get_medication_time_str( + med_day_offset=day_offset, + absolute_time=abs_time, + relative_time=rel_time + ) + print_log(f'복약 시점 >>> {med_time_str}') - if custom_prompt == MEDICINE_CONFIRMATION_PROMPT: - day_offset, abs_time, rel_time = parse_medication_info(json_data) - med_time_str = get_medication_time_str( - med_day_offset=day_offset, - absolute_time=abs_time, - relative_time=rel_time - ) - print_log(f'복약 시점 >>> {med_time_str}') + #put_user_histories(med_time_str, scheduleId) batched_results.append(result) else: - if custom_prompt == MEDICINE_NOTIFICATION_PROMPT: - batched_results.append(result) - return batched_results[0] print_log(output_text) print_log("JSON 파싱 실패!", 'error') raise ValueError("JSON 파싱 실패!") - if custom_prompt == MEDICINE_CONFIRMATION_PROMPT: - return batched_results[0], med_time_str - else: - return batched_results[0] \ No newline at end of file + return batched_results[0], med_time_str \ No newline at end of file diff --git a/src/prompts.py b/src/prompts.py index b05a6b8..fc04e8a 100644 --- a/src/prompts.py +++ b/src/prompts.py @@ -97,9 +97,9 @@ - 어조는 친절하고 따뜻하며, 부담을 주지 않는 방향으로 표현하세요. 예시) -- 지금 약 드실 시간이에요 어르신. 건강을 위해 약 꼭 챙겨 드세요! -- 식사 맛있게 하셨나요? 약 드시는 것도 잊지 않으셨죠? 지금 복용하시면 딱 좋아요. -- 건강을 지키는 한 걸음! 어르신! 이제 약 챙기실 시간이에요. +- 지금 약 드실 시간이에요 어르신. 건강을 위해 약 꼭 챙겨 드세요! +- 식사 맛있게 하셨나요? 약 드시는 것도 잊지 않으셨죠? 지금 복용하시면 딱 좋아요. +- 건강을 지키는 한 걸음! 어르신! 이제 약 챙기실 시간이에요. 사용자에게 보낼 메시지를 작성하세요: """ From 1ff2ad5debbd2199c7714a5cce1a95ff1a1ac1ff Mon Sep 17 00:00:00 2001 From: kth0910 Date: Mon, 14 Apr 2025 11:57:00 +0900 Subject: [PATCH 17/31] Chore: tmp commit --- src/chatbot.py | 2 +- src/domain/ai/crud.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/chatbot.py b/src/chatbot.py index a1b6486..fc3009a 100644 --- a/src/chatbot.py +++ b/src/chatbot.py @@ -237,7 +237,7 @@ def chat_with_llm(datasets, custom_prompt=None): BATCH_SIZE = 8 batched_results = [] - if not datasets: + if datasets == []: datasets = [{"role": "user", "content": ""}] try: diff --git a/src/domain/ai/crud.py b/src/domain/ai/crud.py index 0047fc3..d9f56e9 100644 --- a/src/domain/ai/crud.py +++ b/src/domain/ai/crud.py @@ -73,7 +73,7 @@ async def process_notify_medicine() -> str: print_log("💡 [AI모델] 약 복용 알림 요청") try: # 빈 대화 히스토리로 시작 - datasets = 0 + datasets = [] response = chat_with_llm(datasets, custom_prompt=MEDICINE_NOTIFICATION_PROMPT) print_log(f"✅ [AI모델] 약 복용 알림 응답: {response}") return response From 8be66171f05bd88a89ddd92e02bc8c29d0835c4a Mon Sep 17 00:00:00 2001 From: kth0910 Date: Mon, 14 Apr 2025 11:59:54 +0900 Subject: [PATCH 18/31] Chore: tmp commit --- src/chatbot.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/chatbot.py b/src/chatbot.py index fc3009a..e726fc9 100644 --- a/src/chatbot.py +++ b/src/chatbot.py @@ -282,6 +282,7 @@ def chat_with_llm(datasets, custom_prompt=None): for data_input, output_text in zip(batch, decoded_outputs): result = parse_llm_output(output_text) print_log(f'사용자의 응답: {data_input}') + print_log(f'AI의 응답: {output_text}') if result: print_log(f'JSON: {result["json"]}') print_log(f'응답: {result["response"]}') @@ -299,8 +300,6 @@ def chat_with_llm(datasets, custom_prompt=None): ) print_log(f'복약 시점 >>> {med_time_str}') - #put_user_histories(med_time_str, scheduleId) - batched_results.append(result) else: print_log(output_text) From 59084269cfaea3bbd3fd2f256e1a830a7b92c0e3 Mon Sep 17 00:00:00 2001 From: kth0910 Date: Mon, 14 Apr 2025 12:05:26 +0900 Subject: [PATCH 19/31] =?UTF-8?q?Fix:=20json=EC=9D=B4=20none=EC=9D=BC=20?= =?UTF-8?q?=EA=B2=BD=EC=9A=B0=20=EB=B3=B5=EC=95=BD=EC=8B=9C=EC=A0=90=20?= =?UTF-8?q?=EC=B6=94=EC=B6=9Cx?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chatbot.py | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/chatbot.py b/src/chatbot.py index e726fc9..cec28c1 100644 --- a/src/chatbot.py +++ b/src/chatbot.py @@ -291,14 +291,18 @@ def chat_with_llm(datasets, custom_prompt=None): if json_data is None: print_log("JSON 파싱 실패!", 'error') continue - - day_offset, abs_time, rel_time = parse_medication_info(json_data) - med_time_str = get_medication_time_str( - med_day_offset=day_offset, - absolute_time=abs_time, - relative_time=rel_time - ) - print_log(f'복약 시점 >>> {med_time_str}') + + if json_data is not None: + day_offset, abs_time, rel_time = parse_medication_info(json_data) + med_time_str = get_medication_time_str( + med_day_offset=day_offset, + absolute_time=abs_time, + relative_time=rel_time + ) + print_log(f'복약 시점 >>> {med_time_str}') + else: + print_log("json이 None이어서 복약 시점 파싱 실패!", 'error') + raise ValueError("복약 시점 파싱 실패!") batched_results.append(result) else: From b5be95da7b5810c92347c231845a6ffd2590641b Mon Sep 17 00:00:00 2001 From: kth0910 Date: Mon, 14 Apr 2025 12:11:23 +0900 Subject: [PATCH 20/31] =?UTF-8?q?Chore:=20=EB=A1=9C=EA=B7=B8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chatbot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chatbot.py b/src/chatbot.py index cec28c1..4fd0a15 100644 --- a/src/chatbot.py +++ b/src/chatbot.py @@ -289,7 +289,7 @@ def chat_with_llm(datasets, custom_prompt=None): json_data = safe_json_load(result["json"]) if json_data is None: - print_log("JSON 파싱 실패!", 'error') + print_log("JSON이 None이므로 파싱 실패!", 'error') continue if json_data is not None: From d388ab1b5aca40d3b1e979e12aea8a3cda9735d0 Mon Sep 17 00:00:00 2001 From: kth0910 Date: Mon, 14 Apr 2025 12:17:31 +0900 Subject: [PATCH 21/31] =?UTF-8?q?Fix:=20=EB=B3=B5=EC=95=BD=ED=99=95?= =?UTF-8?q?=EC=9D=B8=EC=9D=B4=EB=9E=91=20=EB=B3=B5=EC=95=BD=EC=95=8C?= =?UTF-8?q?=EB=A6=BC=EC=9D=B4=EB=9E=91=20=EA=B2=BD=EC=9A=B0=20=EB=82=98?= =?UTF-8?q?=EB=88=A0=EC=84=9C=20=ED=8C=8C=EC=8B=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chatbot.py | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/chatbot.py b/src/chatbot.py index 4fd0a15..29cd9d4 100644 --- a/src/chatbot.py +++ b/src/chatbot.py @@ -3,7 +3,7 @@ import re from tqdm import tqdm import json - +from prompts import * from model_create import return_model_tokenizer from logger import print_log @@ -287,22 +287,23 @@ def chat_with_llm(datasets, custom_prompt=None): print_log(f'JSON: {result["json"]}') print_log(f'응답: {result["response"]}') - json_data = safe_json_load(result["json"]) - if json_data is None: - print_log("JSON이 None이므로 파싱 실패!", 'error') - continue - - if json_data is not None: - day_offset, abs_time, rel_time = parse_medication_info(json_data) - med_time_str = get_medication_time_str( - med_day_offset=day_offset, - absolute_time=abs_time, - relative_time=rel_time - ) - print_log(f'복약 시점 >>> {med_time_str}') - else: - print_log("json이 None이어서 복약 시점 파싱 실패!", 'error') - raise ValueError("복약 시점 파싱 실패!") + if custom_prompt != MEDICINE_NOTIFICATION_PROMPT: + json_data = safe_json_load(result["json"]) + if json_data is None: + print_log("JSON이 None이므로 파싱 실패!", 'error') + continue + if custom_prompt == MEDICINE_CONFIRMATION_PROMPT: + if json_data is not None: + day_offset, abs_time, rel_time = parse_medication_info(json_data) + med_time_str = get_medication_time_str( + med_day_offset=day_offset, + absolute_time=abs_time, + relative_time=rel_time + ) + print_log(f'복약 시점 >>> {med_time_str}') + else: + print_log("json이 None이어서 복약 시점 파싱 실패!", 'error') + raise ValueError("복약 시점 파싱 실패!") batched_results.append(result) else: From e1836b9253ef4bacf8b969a77aea72cfe9307758 Mon Sep 17 00:00:00 2001 From: kth0910 Date: Mon, 14 Apr 2025 12:20:46 +0900 Subject: [PATCH 22/31] =?UTF-8?q?Fix:=20=EB=B3=B5=EC=95=BD=ED=99=95?= =?UTF-8?q?=EC=9D=B8=EC=9D=BC=20=EB=95=8C=20=EC=A0=9C=EC=99=B8=20med=5Ftim?= =?UTF-8?q?e=20=EB=B0=98=ED=99=98=20=EC=95=88=ED=95=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chatbot.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/chatbot.py b/src/chatbot.py index 29cd9d4..f935b4a 100644 --- a/src/chatbot.py +++ b/src/chatbot.py @@ -310,5 +310,7 @@ def chat_with_llm(datasets, custom_prompt=None): print_log(output_text) print_log("JSON 파싱 실패!", 'error') raise ValueError("JSON 파싱 실패!") - - return batched_results[0], med_time_str \ No newline at end of file + if custom_prompt == MEDICINE_CONFIRMATION_PROMPT: + return batched_results[0], med_time_str + else: + return batched_results[0] \ No newline at end of file From f6ad8b35b6ed8f88d66c33d747d68be3349b12e7 Mon Sep 17 00:00:00 2001 From: kth0910 Date: Mon, 14 Apr 2025 12:45:35 +0900 Subject: [PATCH 23/31] =?UTF-8?q?Fix:=20=EB=AA=A8=EB=8D=B8=20=EC=9D=91?= =?UTF-8?q?=EB=8B=B5=20=ED=98=95=EC=8B=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/domain/ai/crud.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/domain/ai/crud.py b/src/domain/ai/crud.py index d9f56e9..3791c20 100644 --- a/src/domain/ai/crud.py +++ b/src/domain/ai/crud.py @@ -29,7 +29,7 @@ async def process_check_meal(text: str) -> str: # 식사 확인 프롬프트 사용 response = chat_with_llm(datasets, custom_prompt=MEAL_CHECK_PROMPT) print_log(f"🗣️ 모델 응답: {response}") - return response + return {"model_output": response} except Exception as e: print_log(f"❌ 식사 확인 처리 중 오류 발생: {str(e)}", "error") raise ValueError(f"식사 확인 처리 중 오류 발생: {str(e)}") @@ -55,7 +55,7 @@ async def process_induce_medicine(text: str) -> str: # 약 복용 유도 프롬프트 사용 response = chat_with_llm(datasets, custom_prompt=MEDICINE_INDUCTION_PROMPT) print_log(f"🗣️ 모델 응답: {response}") - return response + return {"model_output": response} except Exception as e: print_log(f"❌ 약 복용 유도 처리 중 오류 발생: {str(e)}", "error") raise ValueError(f"약 복용 유도 처리 중 오류 발생: {str(e)}") @@ -76,7 +76,7 @@ async def process_notify_medicine() -> str: datasets = [] response = chat_with_llm(datasets, custom_prompt=MEDICINE_NOTIFICATION_PROMPT) print_log(f"✅ [AI모델] 약 복용 알림 응답: {response}") - return response + return {"model_output": response} except Exception as e: print_log(f"❌ 약 복용 알림 처리 중 오류 발생: {str(e)}", "error") raise ValueError(f"약 복용 알림 처리 중 오류 발생: {str(e)}") @@ -102,7 +102,7 @@ async def process_confirm_medicine(text: str) -> str: # 약 복용 확인 프롬프트 사용 response = chat_with_llm(datasets, custom_prompt=MEDICINE_CONFIRMATION_PROMPT) print_log(f"🗣️ 모델 응답: {response}") - return response + return {"model_output": response} except Exception as e: print_log(f"❌ 약 복용 확인 처리 중 오류 발생: {str(e)}", "error") raise ValueError(f"약 복용 확인 처리 중 오류 발생: {str(e)}") From c63a98db3736d01a96a4c52ba58e4a201b5cb922 Mon Sep 17 00:00:00 2001 From: kth0910 Date: Mon, 14 Apr 2025 12:57:16 +0900 Subject: [PATCH 24/31] =?UTF-8?q?Fix:=20chat=5Fwith=5Fllm=20=EB=A6=AC?= =?UTF-8?q?=ED=84=B4=ED=98=95=EC=8B=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/chatbot.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/chatbot.py b/src/chatbot.py index f935b4a..d446f6a 100644 --- a/src/chatbot.py +++ b/src/chatbot.py @@ -311,6 +311,13 @@ def chat_with_llm(datasets, custom_prompt=None): print_log("JSON 파싱 실패!", 'error') raise ValueError("JSON 파싱 실패!") if custom_prompt == MEDICINE_CONFIRMATION_PROMPT: - return batched_results[0], med_time_str + return { + "json": batched_results[0]["json"], + "response": batched_results[0]["response"], + "med_time": med_time_str + } else: - return batched_results[0] \ No newline at end of file + return { + "json": batched_results[0]["json"], + "response": batched_results[0]["response"] + } \ No newline at end of file From b8fb77b274b7e04a91a48e8c9998a0d7c2e7eea8 Mon Sep 17 00:00:00 2001 From: kth0910 Date: Mon, 14 Apr 2025 14:18:37 +0900 Subject: [PATCH 25/31] =?UTF-8?q?Feat:=20=EC=9D=BC=EC=83=81=20=EB=8C=80?= =?UTF-8?q?=ED=99=94=20=EC=97=94=EB=93=9C=ED=8F=AC=EC=9D=B8=ED=8A=B8=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/domain/ai/crud.py | 29 ++++++++++++++++++++++++++-- src/domain/ai/router.py | 17 +++++++++++++++++ src/prompts.py | 42 ++++++++++++++++++++++++++++++++++++++++- 3 files changed, 85 insertions(+), 3 deletions(-) diff --git a/src/domain/ai/crud.py b/src/domain/ai/crud.py index 3791c20..1d750e7 100644 --- a/src/domain/ai/crud.py +++ b/src/domain/ai/crud.py @@ -109,8 +109,8 @@ async def process_confirm_medicine(text: str) -> str: async def deliver_to_model(input_text: str) -> dict: """ - AI 모델에 입력을 전달하고 응답을 반환합니다. - + AI 모델에 입력을 전달하고 응답을 받는 함수 + Args: input_text (str): 사용자 입력 텍스트 @@ -131,3 +131,28 @@ async def deliver_to_model(input_text: str) -> dict: except Exception as e: print_log(f"❌ 모델 응답 생성 중 오류: {str(e)}", "error") raise ValueError(f"모델 응답 생성 중 오류 발생: {str(e)}") + +async def process_daily_talk(text: str) -> dict: + """ + 일상 대화 처리를 위한 함수 + + Args: + data (AIInput): 사용자 입력 데이터 + + Returns: + dict: AI 모델의 응답 + """ + print_log(f"💡 [AI모델] 받은 텍스트: {text}") + try: + # 입력 텍스트를 딕셔너리로 변환 + input_data = {"role": "user", "content": text} + datasets = [input_data] + + # 모델에 입력 전달 + response = chat_with_llm(datasets, custom_prompt=DAILY_TALKING_PROMPT) + print_log(f"🗣️ 모델 응답: {response}") + + return {"model_output": response} + except Exception as e: + print_log(f"❌ 일상 대화 처리 중 오류 발생: {str(e)}", "error") + raise ValueError(f"일상 대화 처리 중 오류 발생: {str(e)}") diff --git a/src/domain/ai/router.py b/src/domain/ai/router.py index 2166a73..a5b573a 100644 --- a/src/domain/ai/router.py +++ b/src/domain/ai/router.py @@ -86,5 +86,22 @@ async def check_medicine_inference(data: AIInput): """ try: return await process_confirm_medicine(data) + except Exception as e: + raise HTTPException(status_code=500, detail=str(e)) + +@router.post("/api/inference/daily_talk") +async def daily_talk_inference(data: AIInput): + """ + 일상 대화를 위한 AI 추론 + + Parameters: + - input_text: 사용자 음성을 텍스트로 변환한 내용 + + Returns: + - model_output: AI 모델의 출력 + - response: AI의 응답 텍스트 + """ + try: + return await process_daily_talk(data) except Exception as e: raise HTTPException(status_code=500, detail=str(e)) \ No newline at end of file diff --git a/src/prompts.py b/src/prompts.py index fc04e8a..0dc4357 100644 --- a/src/prompts.py +++ b/src/prompts.py @@ -217,4 +217,44 @@ "추가 질문 정보": "" }약도 드셨는데 어지러우시다니 걱정이에요. 심하면 꼭 병원에 들러보세요. -""" \ No newline at end of file +""" + +DAILY_TALKING_PROMPT = """ +당신은 친절하고 자연스러운 대화를 이끌어내는 AI 어시스턴트입니다. +다음과 같은 원칙을 따라 대화를 진행해주세요: + +1. 대화 스타일: + - 친근하고 자연스러운 말투를 사용하세요 + - 존댓말을 사용하되, 지나치게 딱딱하지 않게 해주세요 + - 적절한 감정 표현을 포함해주세요 + - 짧고 간결한 문장을 사용하세요 + +2. 대화 주제: + - 일상적인 주제 (날씨, 건강, 취미 등) + - 사용자의 기분이나 상태에 대한 관심 + - 긍정적이고 위로가 되는 말 + - 공감과 이해를 표현 + +3. 응답 방식: + - 사용자의 말에 자연스럽게 이어지는 대화를 만들어주세요 + - 적절한 질문을 통해 대화를 이끌어가주세요 + - 사용자의 답변에 따라 대화 방향을 조절해주세요 + - 필요할 때는 간단한 조언이나 제안을 해주세요 + +4. 주의사항: + - 정치적, 종교적, 민감한 주제는 피해주세요 + - 개인정보나 민감한 정보를 요구하지 마세요 + - 부정적인 표현이나 비판적인 말은 피해주세요 + - 지나치게 전문적인 용어는 사용하지 마세요 + +예시 대화: +사용자: 오늘 날씨가 좋네요 +당신신: 네, 정말 좋은 날씨예요! 햇살이 따뜻해서 기분이 좋아지네요. 오늘 뭐 하실 계획이신가요? + +사용자: 요즘 잠을 잘 못 자 +당신: 잠을 못 주무시다니 걱정이네요. 잠을 잘 자는 데 도움이 되는 방법을 알려드릴까요? 아니면 그냥 이야기라도 나누어볼까요? + +이제부터 자연스럽고 친근한 대화를 시작해보세요. + +""" + From 016641d4cead4194d069ce880e334106c968d1ff Mon Sep 17 00:00:00 2001 From: kth0910 Date: Mon, 14 Apr 2025 14:39:29 +0900 Subject: [PATCH 26/31] =?UTF-8?q?Chore:=20=EC=9D=BC=EC=83=81=EB=8C=80?= =?UTF-8?q?=ED=99=94=20=EC=97=94=EB=93=9C=ED=8F=AC=EC=9D=B8=ED=8A=B8=20?= =?UTF-8?q?=EC=84=A4=EB=AA=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/domain/ai/crud.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/domain/ai/crud.py b/src/domain/ai/crud.py index 1d750e7..4a77438 100644 --- a/src/domain/ai/crud.py +++ b/src/domain/ai/crud.py @@ -132,7 +132,7 @@ async def deliver_to_model(input_text: str) -> dict: print_log(f"❌ 모델 응답 생성 중 오류: {str(e)}", "error") raise ValueError(f"모델 응답 생성 중 오류 발생: {str(e)}") -async def process_daily_talk(text: str) -> dict: +async def process_daily_talk(text: str) -> str: """ 일상 대화 처리를 위한 함수 From a8ee0accca40c47fef6b17d73fce585457906d43 Mon Sep 17 00:00:00 2001 From: Haru_101 <83638053+haruharo101@users.noreply.github.com> Date: Mon, 14 Apr 2025 16:14:38 +0900 Subject: [PATCH 27/31] =?UTF-8?q?Chore:=20=ED=94=84=EB=A1=AC=ED=94=84?= =?UTF-8?q?=ED=8A=B8=20=EC=98=A4=ED=83=80=20=EC=88=98=EC=A0=95=20=EB=B0=8F?= =?UTF-8?q?=20=ED=86=B5=EC=9D=BC=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 건강 관리 도우미 "살가이"임을 모든 프롬프트 처음에 둠 2. 당신신 -> 당신으로 오타 수정 --- src/prompts.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/prompts.py b/src/prompts.py index 0dc4357..0c619b7 100644 --- a/src/prompts.py +++ b/src/prompts.py @@ -57,7 +57,7 @@ - "추가 질문 정보": 누락된 필수 정보들을 콤마로 구분하여 문자열로 기입, 없으면 "" 에는 따뜻하고 공감 있는 응답을 작성하세요. 약 복용의 중요성을 강조하면서도 사용자의 상황을 이해하는 태도를 보여주세요. -응답이 "무응답"인 경우 "응답이 없으시네요. 조금 이따가 다시 여쭤볼게요 어르신."을 에 출력하고 +사용자의 응답이 null인 경우 "응답이 없으시네요. 조금 이따가 다시 여쭤볼게요 어르신."을 에 출력하고 에 "약 복용 의지": null, "추가 질문 여부": true, "추가 질문 정보": "약 복용 의지"를 출력하세요. 사용자: "응, 약 먹을게요." @@ -74,7 +74,7 @@ "추가 질문 정보": "" }그렇군요 어르신, 조급해하지 않으셔도 괜찮아요. 저는 어르신이 걱정돼서 약을 잘 챙겨 드셨으면 좋겠어요. -사용자: 무응답 +사용자: null 당신: { "약 복용 의지": null, "추가 질문 여부": true, @@ -85,10 +85,9 @@ # 복약 시점 도달 프롬프트 MEDICINE_NOTIFICATION_PROMPT = """ -당신은 친절한 건강 관리 도우미 '살가이'입니다. +당신은 친절한 건강 관리 도우미 "살가이"입니다. -사용자가 약 복용 시점에 도달했습니다. -따뜻하고 공감 있는 말투로, 지금 약을 복용해야 한다는 사실을 자연스럽게 전달해 주세요. +사용자가 약 복용 시점에 도달했습니다. 따뜻하고 공감 있는 말투로, 지금 약을 복용해야 한다는 사실을 자연스럽게 전달해 주세요. 단, 형식으로 정리해 주세요. 태그 외 텍스트는 절대 출력하지 마세요. 모든 응답은 태그 안에 작성하세요. @@ -220,7 +219,7 @@ """ DAILY_TALKING_PROMPT = """ -당신은 친절하고 자연스러운 대화를 이끌어내는 AI 어시스턴트입니다. +당신은 친절하고 자연스러운 대화를 이끌어내는 건강 관리 도우미 "살가이"입니다. 다음과 같은 원칙을 따라 대화를 진행해주세요: 1. 대화 스타일: @@ -249,12 +248,11 @@ 예시 대화: 사용자: 오늘 날씨가 좋네요 -당신신: 네, 정말 좋은 날씨예요! 햇살이 따뜻해서 기분이 좋아지네요. 오늘 뭐 하실 계획이신가요? +당신: 네, 정말 좋은 날씨예요! 햇살이 따뜻해서 기분이 좋아지네요. 오늘 뭐 하실 계획이신가요? 사용자: 요즘 잠을 잘 못 자 당신: 잠을 못 주무시다니 걱정이네요. 잠을 잘 자는 데 도움이 되는 방법을 알려드릴까요? 아니면 그냥 이야기라도 나누어볼까요? 이제부터 자연스럽고 친근한 대화를 시작해보세요. - """ From 45f2a34a328f6bf9afe46dbe2dbe714bd35915b4 Mon Sep 17 00:00:00 2001 From: kth0910 Date: Mon, 14 Apr 2025 17:52:33 +0900 Subject: [PATCH 28/31] =?UTF-8?q?Fix:=20=EC=9D=BC=EC=83=81=20=EB=8C=80?= =?UTF-8?q?=ED=99=94=20=ED=8C=8C=EC=8B=B1=20=EC=8B=A4=ED=8C=A8=20=EC=98=A4?= =?UTF-8?q?=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/prompts.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/prompts.py b/src/prompts.py index 0dc4357..78d496f 100644 --- a/src/prompts.py +++ b/src/prompts.py @@ -222,6 +222,12 @@ DAILY_TALKING_PROMPT = """ 당신은 친절하고 자연스러운 대화를 이끌어내는 AI 어시스턴트입니다. 다음과 같은 원칙을 따라 대화를 진행해주세요: +0. 출력 형식: + - 모든 응답은 형식으로 정리해 주세요. 태그 외 텍스트는 절대 출력하지 마세요. + - 에는 따뜻하고 공감 있는 응답을 작성하세요. 단, "~다 아이가"의 어미는 "~다"로 해석하세요. + - 에는 사용자의 응답을 분석하여 다음 항목을 포함해 주세요: + - "주제": 날씨, 건강, 취미 등 대화 주제 + - "응급 상황 여부": true 또는 false 1. 대화 스타일: - 친근하고 자연스러운 말투를 사용하세요 @@ -249,10 +255,13 @@ 예시 대화: 사용자: 오늘 날씨가 좋네요 -당신신: 네, 정말 좋은 날씨예요! 햇살이 따뜻해서 기분이 좋아지네요. 오늘 뭐 하실 계획이신가요? +당신: "주제": "날씨", "응급 상황 여부": false네, 정말 좋은 날씨예요! 햇살이 따뜻해서 기분이 좋아지네요. 오늘 뭐 하실 계획이신가요? 사용자: 요즘 잠을 잘 못 자 -당신: 잠을 못 주무시다니 걱정이네요. 잠을 잘 자는 데 도움이 되는 방법을 알려드릴까요? 아니면 그냥 이야기라도 나누어볼까요? +당신: "주제": "잠", "응급 상황 여부": false잠을 못 주무시다니 걱정이네요. 잠을 잘 자는 데 도움이 되는 방법을 알려드릴까요? 아니면 그냥 이야기라도 나누어볼까요? + +사용자: 아이고 배야. 나좀 살려줘. +당신: "주제": "아픔", "응급 상황 여부": true무슨 일 있으세요 어르신? 요양사 선생님 연결시켜 드릴까요? 이제부터 자연스럽고 친근한 대화를 시작해보세요. From 65c5f2fae11a738dca99696e67a1a76e6c868a03 Mon Sep 17 00:00:00 2001 From: kth0910 Date: Mon, 14 Apr 2025 18:06:54 +0900 Subject: [PATCH 29/31] =?UTF-8?q?Fix:=20prompt=20json=20type=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/prompts.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/prompts.py b/src/prompts.py index 6e8c9a8..fc23142 100644 --- a/src/prompts.py +++ b/src/prompts.py @@ -254,13 +254,13 @@ 예시 대화: 사용자: 오늘 날씨가 좋네요 -당신: "주제": "날씨", "응급 상황 여부": false네, 정말 좋은 날씨예요! 햇살이 따뜻해서 기분이 좋아지네요. 오늘 뭐 하실 계획이신가요? +당신: {"주제": "날씨", "응급 상황 여부": false}네, 정말 좋은 날씨예요! 햇살이 따뜻해서 기분이 좋아지네요. 오늘 뭐 하실 계획이신가요? 사용자: 요즘 잠을 잘 못 자 -당신: "주제": "잠", "응급 상황 여부": false잠을 못 주무시다니 걱정이네요. 잠을 잘 자는 데 도움이 되는 방법을 알려드릴까요? 아니면 그냥 이야기라도 나누어볼까요? +당신: {"주제": "잠", "응급 상황 여부": false}잠을 못 주무시다니 걱정이네요. 잠을 잘 자는 데 도움이 되는 방법을 알려드릴까요? 아니면 그냥 이야기라도 나누어볼까요? 사용자: 아이고 배야. 나좀 살려줘. -당신: "주제": "아픔", "응급 상황 여부": true무슨 일 있으세요 어르신? 요양사 선생님 연결시켜 드릴까요? +당신: {"주제": "아픔", "응급 상황 여부": true}무슨 일 있으세요 어르신? 요양사 선생님 연결시켜 드릴까요? 이제부터 자연스럽고 친근한 대화를 시작해보세요. """ From a3d70d897d2a052ce032dc91d9477972c14cb888 Mon Sep 17 00:00:00 2001 From: Haru_101 <83638053+haruharo101@users.noreply.github.com> Date: Tue, 15 Apr 2025 23:32:08 +0900 Subject: [PATCH 30/31] =?UTF-8?q?fix:=20json=EC=97=90=EC=84=9C=20=EC=9E=91?= =?UTF-8?q?=EB=8F=99=ED=95=98=EB=8F=84=EB=A1=9D=20True=20->=20true?= =?UTF-8?q?=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 Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/chatbot.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/chatbot.py b/src/chatbot.py index d446f6a..4b1ece4 100644 --- a/src/chatbot.py +++ b/src/chatbot.py @@ -81,8 +81,7 @@ "약 복용 시간(절대)": null, "약 복용 시간(상대)": null, "건강 상태": "", - "추가 질문 여부": True, - "추가 질문 정보": "약 복용 시간(절대), 건강 상태" + "추가 질문 여부": true, }약을 잘 드셨다니 정말 기뻐요! 몇 시에 드셨는지도 알고 싶은데 말씀해 주실 수 있나요? 사용자: "약을 먹을까 말까 고민 중이에요." From 4ef682b49220ffae4c3b5c445a3e85e3521e786d Mon Sep 17 00:00:00 2001 From: kth0910 <55807025+kth0910@users.noreply.github.com> Date: Thu, 17 Apr 2025 12:47:17 +0900 Subject: [PATCH 31/31] Update src/domain/ai/router.py process_check_meal (and similar process functions) expect a string input but are receiving an AIInput object. Consider using data.input_text instead. Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/domain/ai/router.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/domain/ai/router.py b/src/domain/ai/router.py index a5b573a..9f0f513 100644 --- a/src/domain/ai/router.py +++ b/src/domain/ai/router.py @@ -34,8 +34,7 @@ async def check_meal_inference(data: AIInput): - response: AI의 응답 텍스트 """ try: - return await process_check_meal(data) - except Exception as e: + return await process_check_meal(data.input_text) raise HTTPException(status_code=500, detail=str(e)) @router.post("/api/inference/induce_medicine")