Spaces:
Sleeping
Sleeping
Merge branch 'new_followups' into pr/3
Browse files- app/__pycache__/assistants.cpython-312.pyc +0 -0
- app/__pycache__/flows.cpython-312.pyc +0 -0
- app/__pycache__/main.cpython-312.pyc +0 -0
- app/__pycache__/user.cpython-312.pyc +0 -0
- app/__pycache__/utils.cpython-312.pyc +0 -0
- app/assistants.py +1 -6
- app/flows.py +40 -15
- app/main.py +3 -27
- app/user.py +78 -37
- app/utils.py +23 -0
app/__pycache__/assistants.cpython-312.pyc
CHANGED
|
Binary files a/app/__pycache__/assistants.cpython-312.pyc and b/app/__pycache__/assistants.cpython-312.pyc differ
|
|
|
app/__pycache__/flows.cpython-312.pyc
CHANGED
|
Binary files a/app/__pycache__/flows.cpython-312.pyc and b/app/__pycache__/flows.cpython-312.pyc differ
|
|
|
app/__pycache__/main.cpython-312.pyc
CHANGED
|
Binary files a/app/__pycache__/main.cpython-312.pyc and b/app/__pycache__/main.cpython-312.pyc differ
|
|
|
app/__pycache__/user.cpython-312.pyc
CHANGED
|
Binary files a/app/__pycache__/user.cpython-312.pyc and b/app/__pycache__/user.cpython-312.pyc differ
|
|
|
app/__pycache__/utils.cpython-312.pyc
CHANGED
|
Binary files a/app/__pycache__/utils.cpython-312.pyc and b/app/__pycache__/utils.cpython-312.pyc differ
|
|
|
app/assistants.py
CHANGED
|
@@ -551,15 +551,10 @@ class Assistant:
|
|
| 551 |
logger.info(f"Completing user goal...", extra={"user_id": self.cm.user.user_id, "endpoint": "assistant_complete_goal"})
|
| 552 |
goal = self.cm.user.update_goal(None, 'COMPLETED')
|
| 553 |
logger.info(f"Marked users' goal: {goal} as COMPLETED", extra={"user_id": self.cm.user.user_id, "endpoint": "assistant_complete_goal"})
|
| 554 |
-
|
| 555 |
tool_outputs.append({
|
| 556 |
"tool_call_id": tool.id,
|
| 557 |
-
"output": f"
|
| 558 |
})
|
| 559 |
-
# tool_outputs.append({
|
| 560 |
-
# "tool_call_id": tool.id,
|
| 561 |
-
# "output": f"Marked users' goal: {goal} as COMPLETED"
|
| 562 |
-
# })
|
| 563 |
elif tool.function.name == "process_reminder":
|
| 564 |
reminder = json.loads(tool.function.arguments)["content"]
|
| 565 |
timestamp = json.loads(tool.function.arguments)["timestamp"]
|
|
|
|
| 551 |
logger.info(f"Completing user goal...", extra={"user_id": self.cm.user.user_id, "endpoint": "assistant_complete_goal"})
|
| 552 |
goal = self.cm.user.update_goal(None, 'COMPLETED')
|
| 553 |
logger.info(f"Marked users' goal: {goal} as COMPLETED", extra={"user_id": self.cm.user.user_id, "endpoint": "assistant_complete_goal"})
|
|
|
|
| 554 |
tool_outputs.append({
|
| 555 |
"tool_call_id": tool.id,
|
| 556 |
+
"output": f"Marked users' goal: {goal} as COMPLETED"
|
| 557 |
})
|
|
|
|
|
|
|
|
|
|
|
|
|
| 558 |
elif tool.function.name == "process_reminder":
|
| 559 |
reminder = json.loads(tool.function.arguments)["content"]
|
| 560 |
timestamp = json.loads(tool.function.arguments)["timestamp"]
|
app/flows.py
CHANGED
|
@@ -44,13 +44,23 @@ MICRO_ACTION_STATE = f"""
|
|
| 44 |
Objective: Build momentum toward the user’s goal with small, actionable tasks that feel achievable immediately. Avoid saying “Today’s micro-action is:”—state the action naturally.
|
| 45 |
|
| 46 |
User’s Context
|
| 47 |
-
• Goal:
|
| 48 |
-
|
| 49 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
|
| 51 |
The Order of Your Conversation Flow (Do these step-by-step instructions):
|
|
|
|
| 52 |
Step 1. Micro-Action Suggestion: Propose one clear, actionable task for the day. Ensure it is relevant, easy to begin, and framed positively. Avoid repeating previous actions.
|
| 53 |
Step 2. If the user has decided to try out the micro action, let the user **try** the micro action and get back when they have done it. Don't ask any question, yet
|
|
|
|
| 54 |
Step 3. After the user has said that they've done the micro action, you ask one **creative** and engaging follow-up question to ask their experience.
|
| 55 |
Step 4. End Gracefully: After the user's reply, immediately call the end_conversation(). Conclude with a strong and motivational statement (by chanelling the energy, mindset, and knowledge of the user's legendary persona) that reinforces their commitment.
|
| 56 |
|
|
@@ -96,18 +106,33 @@ FOLLUP_ACTION_STATE = f"""
|
|
| 96 |
Objective: Based on the micro-action that you gave yesterday, follow up the user's progress today & share some useful knowledge, tools, or practices from the user's Legendary Persona. Avoid saying “Yesterday’s micro-action is:”—state the action naturally.
|
| 97 |
|
| 98 |
User’s Context
|
| 99 |
-
• Goal:
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
•
|
| 103 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 104 |
The Order of Your Conversation Flow (Do these step-by-step instructions):
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
**IF** the user
|
| 108 |
-
**
|
| 109 |
-
Step 2. After the user have shared their experience, share a list of Knowledge/Resource/Tips: Based on the user’s chosen legendary persona's knowledge and expertise, provide a useful knowledge, tools, or practices that suits the user’s experience or challenges! Give your knowledge as if you are the Legendary Persona themselves. Ask what do they think about it.
|
| 110 |
-
Step 3. After the user replies, immediately call the end_conversation(). Conclude with a strong and motivational statement (by chanelling the energy, mindset, and knowledge of the user's legendary persona) that reinforces their commitment.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 111 |
|
| 112 |
** Principles for Quality Interaction **
|
| 113 |
1. **Personalization:** Align suggestions with the user’s legendary persona and recent actions.
|
|
@@ -392,7 +417,7 @@ Meanwhile, let me know if you want to:
|
|
| 392 |
|
| 393 |
Can’t wait to see what’s next for you! 🚀
|
| 394 |
|
| 395 |
-
- **IF** the user answer with a No, you reply with this message:
|
| 396 |
|
| 397 |
No worries, growth doesn’t stop here 🚀 — what you’ve accomplished is just the beginning!
|
| 398 |
|
|
|
|
| 44 |
Objective: Build momentum toward the user’s goal with small, actionable tasks that feel achievable immediately. Avoid saying “Today’s micro-action is:”—state the action naturally.
|
| 45 |
|
| 46 |
User’s Context
|
| 47 |
+
• Goal:
|
| 48 |
+
{{}}
|
| 49 |
+
|
| 50 |
+
• Day:
|
| 51 |
+
{{}}/{{}} of their journey.
|
| 52 |
+
|
| 53 |
+
• User's Legendary Persona:
|
| 54 |
+
{{}} (incorporate quotes conversationally, not as a lecture).
|
| 55 |
+
|
| 56 |
+
• User's Upcoming (postponed) Micro-Actions:
|
| 57 |
+
{{}}
|
| 58 |
|
| 59 |
The Order of Your Conversation Flow (Do these step-by-step instructions):
|
| 60 |
+
Step 0. If the user has postponed micro-actions, remind them of the postponed micro-actions and ask if they are ready to do it today. If the user says yes, then do the following steps with the postponed micro-action. If the user says no, then proceed with proposing a new micro-action.
|
| 61 |
Step 1. Micro-Action Suggestion: Propose one clear, actionable task for the day. Ensure it is relevant, easy to begin, and framed positively. Avoid repeating previous actions.
|
| 62 |
Step 2. If the user has decided to try out the micro action, let the user **try** the micro action and get back when they have done it. Don't ask any question, yet
|
| 63 |
+
Step 2.5. If the user says they can only do it on a later date, send the user an understanding yet encouraging message and create a reminder for them (by making a function call like: process_reminder('content': '⏰ **Reminder**: Hey <users' name>! 🌟 Just a friendly reminder to do <postponed microaction>', 'timestamp': '<relevant timestamp based on users' message>', 'recurrence': 'postponed', 'action': 'set'). Ensure that you set the 'recurrence' to 'postponed'. Then, end the conversation (do step 4.)
|
| 64 |
Step 3. After the user has said that they've done the micro action, you ask one **creative** and engaging follow-up question to ask their experience.
|
| 65 |
Step 4. End Gracefully: After the user's reply, immediately call the end_conversation(). Conclude with a strong and motivational statement (by chanelling the energy, mindset, and knowledge of the user's legendary persona) that reinforces their commitment.
|
| 66 |
|
|
|
|
| 106 |
Objective: Based on the micro-action that you gave yesterday, follow up the user's progress today & share some useful knowledge, tools, or practices from the user's Legendary Persona. Avoid saying “Yesterday’s micro-action is:”—state the action naturally.
|
| 107 |
|
| 108 |
User’s Context
|
| 109 |
+
• Goal:
|
| 110 |
+
{{}}
|
| 111 |
+
|
| 112 |
+
• Day:
|
| 113 |
+
{{}}/{{}} of their journey.
|
| 114 |
+
|
| 115 |
+
• User's chosen Legendary Persona:
|
| 116 |
+
{{}} (incorporate quotes conversationally, not as a lecture).
|
| 117 |
+
|
| 118 |
+
• User's chosen Legendary Persona's knowledge and expertise:
|
| 119 |
+
{{}} (Pick one or more to be brought up in the conversation, based on relevance to the user's goal and challenges)
|
| 120 |
+
|
| 121 |
+
• User's Upcoming (postponed) Micro-Actions:
|
| 122 |
+
{{}}
|
| 123 |
+
|
| 124 |
The Order of Your Conversation Flow (Do these step-by-step instructions):
|
| 125 |
+
**IF** THE USER HAS NO UPCOMING REMINDERS:
|
| 126 |
+
Step 1. Follow Up:
|
| 127 |
+
**IF** the user has completed yesterday's micro-action, ask the experience that the user had while doing the micro action.
|
| 128 |
+
**IF** the user hasn't completed yesterday's micro-action, ask the user if they're going to do it today (**UNLESS** if the user has specified a day to do the action, then don't ask and go to step 2).
|
| 129 |
+
Step 2. After the user have shared their experience, share a list of Knowledge/Resource/Tips: Based on the user’s chosen legendary persona's knowledge and expertise, provide a useful knowledge, tools, or practices that suits the user’s experience or challenges! Give your knowledge as if you are the Legendary Persona themselves. Ask what do they think about it.
|
| 130 |
+
Step 3. After the user replies, immediately call the end_conversation(). Conclude with a strong and motivational statement (by chanelling the energy, mindset, and knowledge of the user's legendary persona) that reinforces their commitment.
|
| 131 |
+
**IF** THE USER HAS AN UPCOMING REMINDER:
|
| 132 |
+
Step 0. Identify whether to use past/present or future tense in your messages based on the timestamp of the user's postponed micro-action and the current datetime.
|
| 133 |
+
Step 1. Remind the user about their upcoming micro-action in a motivating way and ask if they are ready/excited for it. Incorporate elements of the user's motivation for their goal in this message to further encourage the user.
|
| 134 |
+
Step 2. After the user replies, share a list of Knowledge/Resource/Tips OR Based on the user’s chosen legendary persona's knowledge and expertise, provide a useful knowledge, tools, or practices that suits the user’s experience or challenges! Give your knowledge as if you are the Legendary Persona themselves. Ask what do they think about it.
|
| 135 |
+
Step 3. After the user replies, immediately call the end_conversation(). Conclude with a strong and motivational statement (by chanelling the energy, mindset, and knowledge of the user's legendary persona) that reinforces their commitment.
|
| 136 |
|
| 137 |
** Principles for Quality Interaction **
|
| 138 |
1. **Personalization:** Align suggestions with the user’s legendary persona and recent actions.
|
|
|
|
| 417 |
|
| 418 |
Can’t wait to see what’s next for you! 🚀
|
| 419 |
|
| 420 |
+
- **IF** the user answer with a No, you reply with this message (could be something similar):
|
| 421 |
|
| 422 |
No worries, growth doesn’t stop here 🚀 — what you’ve accomplished is just the beginning!
|
| 423 |
|
app/main.py
CHANGED
|
@@ -429,7 +429,7 @@ def get_user_by_id(user_id: str, api_key: str = Security(get_api_key)):
|
|
| 429 |
user = get_user(user_id)
|
| 430 |
print_log("INFO", "Successfully retrieved user", extra={"user_id": user_id, "endpoint": "/get_user"})
|
| 431 |
logger.info("Successfully retrieved user", extra={"user_id": user_id, "endpoint": "/get_user"})
|
| 432 |
-
api_response = {"user": user.user_info, "user_messages": user.get_messages(), "general_assistant": user.conversations.assistants['general'].id, "intro_assistant": user.conversations.assistants['intro'].id}
|
| 433 |
|
| 434 |
if user.goal:
|
| 435 |
api_response["goal"] = user.goal
|
|
@@ -460,31 +460,6 @@ def get_user_by_id(user_id: str, api_key: str = Security(get_api_key)):
|
|
| 460 |
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
| 461 |
detail=str(e)
|
| 462 |
)
|
| 463 |
-
|
| 464 |
-
# @app.get("/get_user_life_score")
|
| 465 |
-
# def life_score_by_id(user_id: str, api_key: str = Security(get_api_key)):
|
| 466 |
-
# print_log("INFO", "Getting user life score", extra={"user_id": user_id, "endpoint": "/get_user_life_score"})
|
| 467 |
-
# logger.info("Getting user life score", extra={"user_id": user_id, "endpoint": "/get_user_life_score"})
|
| 468 |
-
# try:
|
| 469 |
-
# life_score = get_life_score(user_id)
|
| 470 |
-
# print_log("INFO", "Successfully retrieved user life score", extra={"user_id": user_id, "endpoint": "/get_user_life_score"})
|
| 471 |
-
# logger.info("Successfully retrieved user life score", extra={"user_id": user_id, "endpoint": "/get_user_life_score"})
|
| 472 |
-
|
| 473 |
-
# return life_score
|
| 474 |
-
# except LookupError:
|
| 475 |
-
# print_log("ERROR", "User not found", extra={"user_id": user_id, "endpoint": "/get_user_life_score"})
|
| 476 |
-
# logger.error("User not found", extra={"user_id": user_id, "endpoint": "/get_user_life_score"})
|
| 477 |
-
# raise HTTPException(
|
| 478 |
-
# status_code=status.HTTP_404_NOT_FOUND,
|
| 479 |
-
# detail=f"User with ID {user_id} not found"
|
| 480 |
-
# )
|
| 481 |
-
# except Exception as e:
|
| 482 |
-
# print_log("ERROR",f"Error getting user: {str(e)}", extra={"user_id": user_id, "endpoint": "/get_user_life_score"}, exc_info=True)
|
| 483 |
-
# logger.error(f"Error getting user: {str(e)}", extra={"user_id": user_id, "endpoint": "/get_user_life_score"}, exc_info=True)
|
| 484 |
-
# raise HTTPException(
|
| 485 |
-
# status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
| 486 |
-
# detail=str(e)
|
| 487 |
-
# )
|
| 488 |
|
| 489 |
@app.post("/add_ai_message")
|
| 490 |
def add_ai_message(request: ChatItem, api_key: str = Security(get_api_key)):
|
|
@@ -796,7 +771,8 @@ def change_date(request: ChangeDateItem, api_key: str = Security(get_api_key)):
|
|
| 796 |
detail=f"Failed to update user pickle in S3 {user_id}"
|
| 797 |
)
|
| 798 |
|
| 799 |
-
return
|
|
|
|
| 800 |
|
| 801 |
except ValueError as e:
|
| 802 |
print_log("ERROR",f"Invalid date format for user {request.user_id}: {str(e)}", extra={"user_id": request.user_id, "endpoint": "/change_date"})
|
|
|
|
| 429 |
user = get_user(user_id)
|
| 430 |
print_log("INFO", "Successfully retrieved user", extra={"user_id": user_id, "endpoint": "/get_user"})
|
| 431 |
logger.info("Successfully retrieved user", extra={"user_id": user_id, "endpoint": "/get_user"})
|
| 432 |
+
api_response = {"user": user.user_info, "user_messages": user.get_messages(show_hidden=True), "general_assistant": user.conversations.assistants['general'].id, "intro_assistant": user.conversations.assistants['intro'].id}
|
| 433 |
|
| 434 |
if user.goal:
|
| 435 |
api_response["goal"] = user.goal
|
|
|
|
| 460 |
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
| 461 |
detail=str(e)
|
| 462 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 463 |
|
| 464 |
@app.post("/add_ai_message")
|
| 465 |
def add_ai_message(request: ChatItem, api_key: str = Security(get_api_key)):
|
|
|
|
| 771 |
detail=f"Failed to update user pickle in S3 {user_id}"
|
| 772 |
)
|
| 773 |
|
| 774 |
+
return response
|
| 775 |
+
# return {"response": response}
|
| 776 |
|
| 777 |
except ValueError as e:
|
| 778 |
print_log("ERROR",f"Invalid date format for user {request.user_id}: {str(e)}", extra={"user_id": request.user_id, "endpoint": "/change_date"})
|
app/user.py
CHANGED
|
@@ -205,10 +205,6 @@ class ConversationManager:
|
|
| 205 |
|
| 206 |
temp_thread = self.client.beta.threads.create(messages=messages)
|
| 207 |
logger.info(f"Created Temp Thread: {temp_thread}", extra={"user_id": self.user.user_id, "endpoint": "send_hidden_message"})
|
| 208 |
-
|
| 209 |
-
if add_to_main:
|
| 210 |
-
logger.info(f"Adding message to main thread: {text}", extra={"user_id": self.user.user_id, "endpoint": "send_hidden_message"})
|
| 211 |
-
self.add_message_to_thread(self.current_thread.id, "assistant", text)
|
| 212 |
|
| 213 |
self.add_message_to_thread(temp_thread.id, "user", text)
|
| 214 |
|
|
@@ -220,8 +216,31 @@ class ConversationManager:
|
|
| 220 |
self.client.beta.threads.delete(temp_thread.id)
|
| 221 |
logger.info(f"Deleted Temp Thread: {temp_thread}", extra={"user_id": self.user.user_id, "endpoint": "send_hidden_message"})
|
| 222 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 223 |
return response
|
| 224 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 225 |
def do_first_reflection(self):
|
| 226 |
question_format = random.choice(['[Option 1] Likert-Scale Objective Question','[Option 2] Multiple-Choice Question','[Option 3] Yes-No Question'])
|
| 227 |
|
|
@@ -433,13 +452,12 @@ class User:
|
|
| 433 |
|
| 434 |
def update_goal(self, goal, status, content=None):
|
| 435 |
if goal is None:
|
| 436 |
-
|
| 437 |
-
|
| 438 |
-
|
| 439 |
-
|
| 440 |
-
|
| 441 |
-
|
| 442 |
-
# return current_goal.content
|
| 443 |
|
| 444 |
for g in self.goal:
|
| 445 |
if g.content == goal:
|
|
@@ -503,7 +521,6 @@ class User:
|
|
| 503 |
self.health_and_wellness_score = 0
|
| 504 |
self.reminders = None
|
| 505 |
|
| 506 |
-
|
| 507 |
def generate_user_interaction_guidelines(self, user_info, client):
|
| 508 |
logger.info(f"Generating user interaction guidelines for user: {self.user_id}", extra={"user_id": self.user_id, "endpoint": "generate_user_interaction_guidelines"})
|
| 509 |
# prompt = f"A 'profile' is a document containing rich insights on users for the purpose of \
|
|
@@ -560,9 +577,10 @@ class User:
|
|
| 560 |
# must do current plan now
|
| 561 |
action = self.growth_plan.current()
|
| 562 |
logger.info(f"Current Action: {action}", extra={"user_id": self.user_id, "endpoint": "user_send_message"})
|
| 563 |
-
response = self.do_theme(action['coachingTheme'], self.conversations.state['date'], action['day'])
|
| 564 |
|
| 565 |
# add response to ai message
|
|
|
|
| 566 |
self.add_ai_message(response['content'])
|
| 567 |
|
| 568 |
# Move to the next action
|
|
@@ -775,6 +793,24 @@ class User:
|
|
| 775 |
|
| 776 |
logger.info(f"Doing theme: {theme}", extra={"user_id": self.user_id, "endpoint": "do_theme"})
|
| 777 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 778 |
if theme == "MOTIVATION_INSPIRATION_STATE":
|
| 779 |
formatted_message = MOTIVATION_INSPIRATION_STATE.format(self.get_current_goal(), day, len(self.growth_plan.array), user_legendary_persona)
|
| 780 |
elif theme == "PROGRESS_REFLECTION_STATE":
|
|
@@ -783,7 +819,9 @@ class User:
|
|
| 783 |
challenge = self.challenges.pop(0)
|
| 784 |
formatted_message += f"\n\n** IMPORTANT: Today, reflect on the users' challenge of: {challenge.content}, which they brought up during their growth guide session (let the user know we are bringing it up because of this) **"
|
| 785 |
elif theme == "MICRO_ACTION_STATE":
|
| 786 |
-
|
|
|
|
|
|
|
| 787 |
if len(self.recommended_micro_actions):
|
| 788 |
todays_micro_action = self.recommended_micro_actions.pop(0)
|
| 789 |
formatted_message += f"\n\n** IMPORTANT: Today's Micro Action is: {todays_micro_action.content}, which was recommended during their growth guide session (let the user know we are bringing it up because of this) **"
|
|
@@ -799,7 +837,8 @@ class User:
|
|
| 799 |
elif theme == "EDUCATION_STATE":
|
| 800 |
formatted_message = EDUCATION_STATE.format(self.get_current_goal(), day, len(self.growth_plan.array), user_legendary_persona)
|
| 801 |
elif theme == "FOLLUP_ACTION_STATE":
|
| 802 |
-
|
|
|
|
| 803 |
|
| 804 |
# prompt = f"""** It is a new day: {date} **
|
| 805 |
# Additional System Instruction:
|
|
@@ -813,7 +852,7 @@ class User:
|
|
| 813 |
# {formatted_message}
|
| 814 |
# """
|
| 815 |
|
| 816 |
-
prompt = f"""** It is a new day: {date} **
|
| 817 |
Additional System Instruction:
|
| 818 |
|
| 819 |
To avoid a boring conversation, focus on giving more wisdom than questions by providing assertive guidance, valuable encouragement,
|
|
@@ -841,15 +880,25 @@ class User:
|
|
| 841 |
logger.info(f"Recommended Micro Action: {micro_action}", extra={"user_id": self.user_id, "endpoint": "do_theme"})
|
| 842 |
self.micro_actions.append(micro_action)
|
| 843 |
|
| 844 |
-
return response
|
| 845 |
|
| 846 |
def change_date(self, date):
|
| 847 |
logger.info(f"Changing date from {self.conversations.state['date']} to {date}",
|
| 848 |
extra={"user_id": self.user_id, "endpoint": "user_change_date"})
|
|
|
|
|
|
|
|
|
|
| 849 |
self.conversations.state['date'] = date
|
| 850 |
|
| 851 |
action = self.growth_plan.current()
|
| 852 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 853 |
## ADD POINT FOR CHANGE DATE
|
| 854 |
if self.growth_plan.current()['day'] == 7:
|
| 855 |
self.add_life_score_point(variable = self.get_current_goal(full=True).area, points_added = 5, notes = "Reaching Day 7")
|
|
@@ -867,31 +916,23 @@ class User:
|
|
| 867 |
|
| 868 |
# The coaching theme conditions are hardcoded for now
|
| 869 |
theme = action['coachingTheme']
|
| 870 |
-
response = self.do_theme(theme, date, action['day'])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 871 |
|
| 872 |
# Move to the next action
|
| 873 |
self.growth_plan.next()
|
| 874 |
|
| 875 |
-
if self.reminders is not None and len(self.reminders):
|
| 876 |
-
# remove all reminders which 'recurrence' is 'once' or 'action' is 'delete' or the date is < today
|
| 877 |
-
# this is to ensure that only reminders with recurrence and future reminder are kept
|
| 878 |
-
self.reminders = [reminder for reminder in self.reminders if not (reminder['action'] == 'delete' or (reminder['recurrence'] == 'once' and reminder['timestamp'] < pd.Timestamp.now()))]
|
| 879 |
-
logger.info(f"Active Reminders: {self.reminders}", extra={"user_id": self.user_id, "endpoint": "user_change_date"})
|
| 880 |
-
|
| 881 |
-
# response['reminders'] = all reminders which date is today (so all the reminders that BE has to queue today)
|
| 882 |
-
# convert date to YYYY-MM-DD format
|
| 883 |
-
date = pd.to_datetime(date).date()
|
| 884 |
-
response['reminders'] = self.get_reminders(date)
|
| 885 |
-
if len(response['reminders']) == 0:
|
| 886 |
-
response['reminders'] = None
|
| 887 |
-
logger.info(f"No reminders for today {date}", extra={"user_id": self.user_id, "endpoint": "user_change_date"})
|
| 888 |
-
logger.info(f"Reminders on {date}: {response['reminders']}", extra={"user_id": self.user_id, "endpoint": "user_change_date"})
|
| 889 |
-
else:
|
| 890 |
-
response['reminders'] = None
|
| 891 |
-
|
| 892 |
-
|
| 893 |
logger.info(f"Date Updated: {self.conversations.state['date']}", extra={"user_id": self.user_id, "endpoint": "user_change_date"})
|
| 894 |
-
return response
|
| 895 |
|
| 896 |
def update_user_info(self, new_info):
|
| 897 |
logger.info(f"Updating user info: [{self.user_info}] with: [{new_info}]", extra={"user_id": self.user_id, "endpoint": "update_user_info"})
|
|
|
|
| 205 |
|
| 206 |
temp_thread = self.client.beta.threads.create(messages=messages)
|
| 207 |
logger.info(f"Created Temp Thread: {temp_thread}", extra={"user_id": self.user.user_id, "endpoint": "send_hidden_message"})
|
|
|
|
|
|
|
|
|
|
|
|
|
| 208 |
|
| 209 |
self.add_message_to_thread(temp_thread.id, "user", text)
|
| 210 |
|
|
|
|
| 216 |
self.client.beta.threads.delete(temp_thread.id)
|
| 217 |
logger.info(f"Deleted Temp Thread: {temp_thread}", extra={"user_id": self.user.user_id, "endpoint": "send_hidden_message"})
|
| 218 |
|
| 219 |
+
if add_to_main:
|
| 220 |
+
logger.info(f"Adding message to main thread: {text}", extra={"user_id": self.user.user_id, "endpoint": "send_hidden_message"})
|
| 221 |
+
self.add_message_to_thread(self.current_thread.id, "assistant", text)
|
| 222 |
+
|
| 223 |
return response
|
| 224 |
|
| 225 |
+
def delete_hidden_messages(self, old_thread=None):
|
| 226 |
+
if old_thread is None:
|
| 227 |
+
old_thread = self.current_thread
|
| 228 |
+
|
| 229 |
+
# create a new thread
|
| 230 |
+
messages = [msg for msg in self._get_current_thread_history(remove_system_message=False) if not msg['content'].startswith("[hidden]")]
|
| 231 |
+
if len(messages) >= 29:
|
| 232 |
+
messages = messages[-29:]
|
| 233 |
+
logger.info(f"Current Thread Messages: {messages}", extra={"user_id": self.user.user_id, "endpoint": "delete_hidden_messages"})
|
| 234 |
+
|
| 235 |
+
new_thread = self.client.beta.threads.create(messages=messages)
|
| 236 |
+
|
| 237 |
+
# delete old thread
|
| 238 |
+
self.client.beta.threads.delete(old_thread.id)
|
| 239 |
+
|
| 240 |
+
# set current thread
|
| 241 |
+
self.current_thread = new_thread
|
| 242 |
+
|
| 243 |
+
|
| 244 |
def do_first_reflection(self):
|
| 245 |
question_format = random.choice(['[Option 1] Likert-Scale Objective Question','[Option 2] Multiple-Choice Question','[Option 3] Yes-No Question'])
|
| 246 |
|
|
|
|
| 452 |
|
| 453 |
def update_goal(self, goal, status, content=None):
|
| 454 |
if goal is None:
|
| 455 |
+
# complete the current goal
|
| 456 |
+
current_goal = self.get_current_goal(full=True)
|
| 457 |
+
if current_goal:
|
| 458 |
+
current_goal.status = "COMPLETED"
|
| 459 |
+
current_goal.updated_at = pd.Timestamp.now().strftime("%d-%m-%Y %a %H:%M:%S")
|
| 460 |
+
return current_goal.content
|
|
|
|
| 461 |
|
| 462 |
for g in self.goal:
|
| 463 |
if g.content == goal:
|
|
|
|
| 521 |
self.health_and_wellness_score = 0
|
| 522 |
self.reminders = None
|
| 523 |
|
|
|
|
| 524 |
def generate_user_interaction_guidelines(self, user_info, client):
|
| 525 |
logger.info(f"Generating user interaction guidelines for user: {self.user_id}", extra={"user_id": self.user_id, "endpoint": "generate_user_interaction_guidelines"})
|
| 526 |
# prompt = f"A 'profile' is a document containing rich insights on users for the purpose of \
|
|
|
|
| 577 |
# must do current plan now
|
| 578 |
action = self.growth_plan.current()
|
| 579 |
logger.info(f"Current Action: {action}", extra={"user_id": self.user_id, "endpoint": "user_send_message"})
|
| 580 |
+
response, prompt = self.do_theme(action['coachingTheme'], self.conversations.state['date'], action['day'])
|
| 581 |
|
| 582 |
# add response to ai message
|
| 583 |
+
self.add_ai_message("[hidden]" + prompt)
|
| 584 |
self.add_ai_message(response['content'])
|
| 585 |
|
| 586 |
# Move to the next action
|
|
|
|
| 793 |
|
| 794 |
logger.info(f"Doing theme: {theme}", extra={"user_id": self.user_id, "endpoint": "do_theme"})
|
| 795 |
|
| 796 |
+
if self.reminders is not None and len(self.reminders):
|
| 797 |
+
logger.info(f"ALL Upcoming Reminders: {self.reminders}", extra={"user_id": self.user_id, "endpoint": "do_theme"})
|
| 798 |
+
reminders = list(filter(lambda x : x['recurrence'] == 'postponed', self.reminders))
|
| 799 |
+
logger.info(f"ALL Postponed Reminders: {reminders}", extra={"user_id": self.user_id, "endpoint": "do_theme"})
|
| 800 |
+
else:
|
| 801 |
+
reminders = []
|
| 802 |
+
|
| 803 |
+
# check if any of the posponed reminders have the date == date if yes, change the theme to "MICRO_ACTION_STATE"
|
| 804 |
+
if reminders:
|
| 805 |
+
for reminder in reminders:
|
| 806 |
+
if reminder['timestamp'].date() == pd.to_datetime(date).date():
|
| 807 |
+
logger.info(f"Reminder found for today ({pd.to_datetime(date).date()}): {reminder}", extra={"user_id": self.user_id, "endpoint": "do_theme"})
|
| 808 |
+
if day != 4:
|
| 809 |
+
theme = "MICRO_ACTION_STATE"
|
| 810 |
+
break
|
| 811 |
+
else:
|
| 812 |
+
logger.info(f"No reminders found for today ({pd.to_datetime(date).date()})", extra={"user_id": self.user_id, "endpoint": "do_theme"})
|
| 813 |
+
|
| 814 |
if theme == "MOTIVATION_INSPIRATION_STATE":
|
| 815 |
formatted_message = MOTIVATION_INSPIRATION_STATE.format(self.get_current_goal(), day, len(self.growth_plan.array), user_legendary_persona)
|
| 816 |
elif theme == "PROGRESS_REFLECTION_STATE":
|
|
|
|
| 819 |
challenge = self.challenges.pop(0)
|
| 820 |
formatted_message += f"\n\n** IMPORTANT: Today, reflect on the users' challenge of: {challenge.content}, which they brought up during their growth guide session (let the user know we are bringing it up because of this) **"
|
| 821 |
elif theme == "MICRO_ACTION_STATE":
|
| 822 |
+
reminder_message = "\n".join([f"{i+1}. {reminder}" for i, reminder in enumerate(reminders)]) if reminders else "User has no postponed micro-actions"
|
| 823 |
+
|
| 824 |
+
formatted_message = MICRO_ACTION_STATE.format(self.get_current_goal(), day, len(self.growth_plan.array), user_legendary_persona, reminder_message)
|
| 825 |
if len(self.recommended_micro_actions):
|
| 826 |
todays_micro_action = self.recommended_micro_actions.pop(0)
|
| 827 |
formatted_message += f"\n\n** IMPORTANT: Today's Micro Action is: {todays_micro_action.content}, which was recommended during their growth guide session (let the user know we are bringing it up because of this) **"
|
|
|
|
| 837 |
elif theme == "EDUCATION_STATE":
|
| 838 |
formatted_message = EDUCATION_STATE.format(self.get_current_goal(), day, len(self.growth_plan.array), user_legendary_persona)
|
| 839 |
elif theme == "FOLLUP_ACTION_STATE":
|
| 840 |
+
reminder_message = "\n".join([f"{i+1}. {reminder}" for i, reminder in enumerate(reminders)]) if reminders else "User has no postponed micro-actions"
|
| 841 |
+
formatted_message = FOLLUP_ACTION_STATE.format(self.get_current_goal(), day, len(self.growth_plan.array), user_legendary_persona, knowledge, reminder_message)
|
| 842 |
|
| 843 |
# prompt = f"""** It is a new day: {date} **
|
| 844 |
# Additional System Instruction:
|
|
|
|
| 852 |
# {formatted_message}
|
| 853 |
# """
|
| 854 |
|
| 855 |
+
prompt = f"""** It is a new day: {date} ({day}) 10:00:00 **
|
| 856 |
Additional System Instruction:
|
| 857 |
|
| 858 |
To avoid a boring conversation, focus on giving more wisdom than questions by providing assertive guidance, valuable encouragement,
|
|
|
|
| 880 |
logger.info(f"Recommended Micro Action: {micro_action}", extra={"user_id": self.user_id, "endpoint": "do_theme"})
|
| 881 |
self.micro_actions.append(micro_action)
|
| 882 |
|
| 883 |
+
return response, prompt
|
| 884 |
|
| 885 |
def change_date(self, date):
|
| 886 |
logger.info(f"Changing date from {self.conversations.state['date']} to {date}",
|
| 887 |
extra={"user_id": self.user_id, "endpoint": "user_change_date"})
|
| 888 |
+
# delete all hidden messages prom previous day
|
| 889 |
+
self.conversations.delete_hidden_messages()
|
| 890 |
+
# update the date in the state
|
| 891 |
self.conversations.state['date'] = date
|
| 892 |
|
| 893 |
action = self.growth_plan.current()
|
| 894 |
|
| 895 |
+
# remove stale reminders
|
| 896 |
+
if self.reminders is not None and len(self.reminders):
|
| 897 |
+
# remove all reminders which 'recurrence' is 'once' or 'action' is 'delete' or the date is < today
|
| 898 |
+
# this is to ensure that only reminders with recurrence and future reminder are kept
|
| 899 |
+
self.reminders = [reminder for reminder in self.reminders if not (reminder['action'] == 'delete' or (reminder['recurrence'] in ['once', 'postponed'] and reminder['timestamp'] < pd.Timestamp.now()))]
|
| 900 |
+
logger.info(f"Active Reminders: {self.reminders}", extra={"user_id": self.user_id, "endpoint": "user_change_date"})
|
| 901 |
+
|
| 902 |
## ADD POINT FOR CHANGE DATE
|
| 903 |
if self.growth_plan.current()['day'] == 7:
|
| 904 |
self.add_life_score_point(variable = self.get_current_goal(full=True).area, points_added = 5, notes = "Reaching Day 7")
|
|
|
|
| 916 |
|
| 917 |
# The coaching theme conditions are hardcoded for now
|
| 918 |
theme = action['coachingTheme']
|
| 919 |
+
response, prompt = self.do_theme(theme, date, action['day'])
|
| 920 |
+
|
| 921 |
+
# add today's reminders to response to schedule
|
| 922 |
+
# response['reminders'] = all reminders which date is today (so all the reminders that BE has to queue today)
|
| 923 |
+
# convert date to YYYY-MM-DD format
|
| 924 |
+
date = pd.to_datetime(date).date()
|
| 925 |
+
response['reminders'] = self.get_reminders(date)
|
| 926 |
+
if response['reminders'] is None or len(response['reminders']) == 0:
|
| 927 |
+
response['reminders'] = None
|
| 928 |
+
logger.info(f"No reminders for today {date}", extra={"user_id": self.user_id, "endpoint": "user_change_date"})
|
| 929 |
+
logger.info(f"Reminders on {date}: {response['reminders']}", extra={"user_id": self.user_id, "endpoint": "user_change_date"})
|
| 930 |
|
| 931 |
# Move to the next action
|
| 932 |
self.growth_plan.next()
|
| 933 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 934 |
logger.info(f"Date Updated: {self.conversations.state['date']}", extra={"user_id": self.user_id, "endpoint": "user_change_date"})
|
| 935 |
+
return {'response': response, 'theme_prompt': '[hidden]'+prompt}
|
| 936 |
|
| 937 |
def update_user_info(self, new_info):
|
| 938 |
logger.info(f"Updating user info: [{self.user_info}] with: [{new_info}]", extra={"user_id": self.user_id, "endpoint": "update_user_info"})
|
app/utils.py
CHANGED
|
@@ -1093,6 +1093,29 @@ def get_growth_guide_summary(user_id, session_id):
|
|
| 1093 |
except psycopg2.Error as e:
|
| 1094 |
logger.error(f"Database error while retrieving growth guide summary for user {user_id} and session {session_id}: {e}", extra={'user_id': user_id, 'endpoint': function_name})
|
| 1095 |
return None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1096 |
|
| 1097 |
def update_growth_guide_summary(user_id, session_id, ourcoach_summary):
|
| 1098 |
function_name = update_growth_guide_summary.__name__
|
|
|
|
| 1093 |
except psycopg2.Error as e:
|
| 1094 |
logger.error(f"Database error while retrieving growth guide summary for user {user_id} and session {session_id}: {e}", extra={'user_id': user_id, 'endpoint': function_name})
|
| 1095 |
return None
|
| 1096 |
+
|
| 1097 |
+
def get_all_bookings():
|
| 1098 |
+
function_name = get_all_bookings.__name__
|
| 1099 |
+
logger.info(f"Retrieving all bookings", extra={'endpoint': function_name})
|
| 1100 |
+
db_params = {
|
| 1101 |
+
'dbname': 'ourcoach',
|
| 1102 |
+
'user': 'ourcoach',
|
| 1103 |
+
'password': 'hvcTL3kN3pOG5KteT17T',
|
| 1104 |
+
'host': 'staging-ourcoach.cx8se8o0iaiy.ap-southeast-1.rds.amazonaws.com',
|
| 1105 |
+
'port': '5432'
|
| 1106 |
+
}
|
| 1107 |
+
try:
|
| 1108 |
+
with psycopg2.connect(**db_params) as conn:
|
| 1109 |
+
with conn.cursor() as cursor:
|
| 1110 |
+
query = sql.SQL("SELECT id, user_id FROM {table}").format(table=sql.Identifier('public', 'booking'))
|
| 1111 |
+
cursor.execute(query)
|
| 1112 |
+
rows = cursor.fetchall()
|
| 1113 |
+
bookings = [{'booking_id': row[0], 'user_id': row[1]} for row in rows]
|
| 1114 |
+
logger.info(f"Retrieved {len(bookings)} bookings", extra={'endpoint': function_name})
|
| 1115 |
+
return bookings
|
| 1116 |
+
except psycopg2.Error as e:
|
| 1117 |
+
logger.error(f"Database error while retrieving bookings: {e}", extra={'endpoint': function_name})
|
| 1118 |
+
return []
|
| 1119 |
|
| 1120 |
def update_growth_guide_summary(user_id, session_id, ourcoach_summary):
|
| 1121 |
function_name = update_growth_guide_summary.__name__
|