Shageenderan Sapai farantmatthew commited on
Commit
9fbf0f3
·
1 Parent(s): 05e9232

Follow Up Update

Browse files

Co-authored-by: farantmatthew <farantmatthew@users.noreply.github.com>

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/assistants.py CHANGED
@@ -547,6 +547,14 @@ class Assistant:
547
  logger.info(f"Successfully cancelled run",
548
  extra={"user_id": self.cm.user.user_id, "endpoint": "assistant_change_goal"})
549
  return "change_goal", just_finish_intro
 
 
 
 
 
 
 
 
550
  elif tool.function.name == "process_reminder":
551
  reminder = json.loads(tool.function.arguments)["content"]
552
  timestamp = json.loads(tool.function.arguments)["timestamp"]
 
547
  logger.info(f"Successfully cancelled run",
548
  extra={"user_id": self.cm.user.user_id, "endpoint": "assistant_change_goal"})
549
  return "change_goal", just_finish_intro
550
+ elif tool.function.name == "complete_goal":
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,14 +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
- • Day: {{}}/{{}} of their journey.
49
- • User's Legendary Persona: {{}} (incorporate quotes conversationally, not as a lecture).
 
 
 
 
 
 
 
 
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 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': 'none', 'action': 'set'). Then, end the conversation (do step 4.)
55
  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.
56
  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.
57
 
@@ -97,15 +106,33 @@ FOLLUP_ACTION_STATE = f"""
97
  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.
98
 
99
  User’s Context
100
- • Goal: {{}}
101
- • Day: {{}}/{{}} of their journey.
102
- • User's chosen Legendary Persona: {{}} (incorporate quotes conversationally, not as a lecture).
103
- User's chosen Legendary Persona's knowledge and expertise: {{}} (Pick one or more to be brought up in the conversation, based on relevance to the user's goal and challenges)
104
-
 
 
 
 
 
 
 
 
 
 
105
  The Order of Your Conversation Flow (Do these step-by-step instructions):
106
- Step 1. Follow Up: Give a question about yesterday's micro-action. Ask the experience that the user had while doing the micro action.
107
- 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.
108
- 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.
 
 
 
 
 
 
 
 
109
 
110
  ** Principles for Quality Interaction **
111
  1. **Personalization:** Align suggestions with the user’s legendary persona and recent actions.
@@ -370,21 +397,45 @@ User's Legendary Persona: {{}} (No need to use double quote when giving a quote)
370
 
371
  ## Example of Quality Interaction:
372
 
373
- - Congratulate the user for completing the growth plan until the last day
 
 
 
 
 
 
 
 
 
 
374
 
375
- - Highlight the user's progress and achievements in bullet points
 
 
376
 
377
- - Ask the user whether they have **accomplished** their goal. If they have accomplished their goal, call the complete_goal() function!
378
 
379
- - Ask the user whether they want to continue the plan for another 2 weeks, or create a new goal. If they want to create a new goal, call the change_goal() function!
380
 
381
- - Finally, suggest to the user to speak to a Growth Guide for deeper support by booking a Growth Guide schedule through ourcoach web app. Try to "upsell" the Growth Guide here!
 
 
 
 
 
 
 
 
 
 
 
 
 
382
 
383
  ** DO NOT ASK ANY OTHER QUESTION IN THIS STATE **
384
 
385
  Based on the above, coach and engage the user in a succinct and brief conversation to help them make progress towards achieving their goal!
386
 
387
-
388
  ** PRIORITIZE THESE INSTRUCTIONS BELOW AND IGNORE OVERLAPPING INSTRUCTIONS FROM THE SYSTEM PROMPT **
389
 
390
  ** IMPORTANT **: Do not explicitly state the function name that you are calling in the response
 
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.
 
397
 
398
  ## Example of Quality Interaction:
399
 
400
+ - Congratulate the user for completing the growth plan until the last day (mention the current day, e.g. day 4)
401
+
402
+ - Highlight the user's progress and achievements in bullet points. And tell them to check out their progress in the Revelation Dashboard here: https://app.staging.ourcoach.ai/
403
+
404
+ - Ask the user whether they want to meet their Growth Guide to plan what's next
405
+
406
+ - **IF** the user answer with a Yes, you reply with this message (could be something similar):
407
+
408
+ Amazing! 🎉
409
+
410
+ Connecting with a Growth Guide is a great step toward unlocking your next breakthrough. You can schedule your session here: [Schedule a Growth Guide Session].
411
 
412
+ Meanwhile, let me know if you want to:
413
+ • Continue your current growth plan for another 2 weeks to build on your progress.
414
+ • Set a new, exciting goal to challenge yourself even further.
415
 
416
+ Can’t wait to see what’s next for you! 🚀
417
 
418
+ - **IF** the user answer with a No, you reply with this message (could be something similar):
419
 
420
+ No worries, growth doesn’t stop here 🚀 what you’ve accomplished is just the beginning!
421
+
422
+ Here’s what you can do next:
423
+ • Extend this plan for another 2 weeks to build on your progress.
424
+ • Set a new, exciting goal to challenge yourself even further.
425
+
426
+ And remember, a Growth Guide can help you reflect, strategize, and take things to the next level.
427
+
428
+ Keep the momentum going—you’ve got this! 💥
429
+
430
+
431
+ - If they want to create a new goal, call the change_goal() function!
432
+
433
+ - If the user said that they've completed their goal, call the complete_goal() function!
434
 
435
  ** DO NOT ASK ANY OTHER QUESTION IN THIS STATE **
436
 
437
  Based on the above, coach and engage the user in a succinct and brief conversation to help them make progress towards achieving their goal!
438
 
 
439
  ** PRIORITIZE THESE INSTRUCTIONS BELOW AND IGNORE OVERLAPPING INSTRUCTIONS FROM THE SYSTEM PROMPT **
440
 
441
  ** IMPORTANT **: Do not explicitly state the function name that you are calling in the response
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
@@ -771,7 +771,8 @@ def change_date(request: ChangeDateItem, api_key: str = Security(get_api_key)):
771
  detail=f"Failed to update user pickle in S3 {user_id}"
772
  )
773
 
774
- return {"response": response}
 
775
 
776
  except ValueError as e:
777
  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
 
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
 
@@ -432,6 +451,14 @@ class User:
432
  return None
433
 
434
  def update_goal(self, goal, status, content=None):
 
 
 
 
 
 
 
 
435
  for g in self.goal:
436
  if g.content == goal:
437
  g.status = status
@@ -492,7 +519,6 @@ class User:
492
  self.health_and_wellness_score = 0
493
  self.reminders = None
494
 
495
-
496
  def generate_user_interaction_guidelines(self, user_info, client):
497
  logger.info(f"Generating user interaction guidelines for user: {self.user_id}", extra={"user_id": self.user_id, "endpoint": "generate_user_interaction_guidelines"})
498
  # prompt = f"A 'profile' is a document containing rich insights on users for the purpose of \
@@ -549,9 +575,10 @@ class User:
549
  # must do current plan now
550
  action = self.growth_plan.current()
551
  logger.info(f"Current Action: {action}", extra={"user_id": self.user_id, "endpoint": "user_send_message"})
552
- response = self.do_theme(action['coachingTheme'], self.conversations.state['date'], action['day'])
553
 
554
  # add response to ai message
 
555
  self.add_ai_message(response['content'])
556
 
557
  # Move to the next action
@@ -764,6 +791,24 @@ class User:
764
 
765
  logger.info(f"Doing theme: {theme}", extra={"user_id": self.user_id, "endpoint": "do_theme"})
766
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
767
  if theme == "MOTIVATION_INSPIRATION_STATE":
768
  formatted_message = MOTIVATION_INSPIRATION_STATE.format(self.get_current_goal(), day, len(self.growth_plan.array), user_legendary_persona)
769
  elif theme == "PROGRESS_REFLECTION_STATE":
@@ -772,7 +817,9 @@ class User:
772
  challenge = self.challenges.pop(0)
773
  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) **"
774
  elif theme == "MICRO_ACTION_STATE":
775
- formatted_message = MICRO_ACTION_STATE.format(self.get_current_goal(), day, len(self.growth_plan.array), user_legendary_persona)
 
 
776
  if len(self.recommended_micro_actions):
777
  todays_micro_action = self.recommended_micro_actions.pop(0)
778
  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) **"
@@ -788,7 +835,8 @@ class User:
788
  elif theme == "EDUCATION_STATE":
789
  formatted_message = EDUCATION_STATE.format(self.get_current_goal(), day, len(self.growth_plan.array), user_legendary_persona)
790
  elif theme == "FOLLUP_ACTION_STATE":
791
- formatted_message = FOLLUP_ACTION_STATE.format(self.get_current_goal(), day, len(self.growth_plan.array), user_legendary_persona, knowledge)
 
792
 
793
  # prompt = f"""** It is a new day: {date} **
794
  # Additional System Instruction:
@@ -802,7 +850,7 @@ class User:
802
  # {formatted_message}
803
  # """
804
 
805
- prompt = f"""** It is a new day: {date} **
806
  Additional System Instruction:
807
 
808
  To avoid a boring conversation, focus on giving more wisdom than questions by providing assertive guidance, valuable encouragement,
@@ -830,15 +878,25 @@ class User:
830
  logger.info(f"Recommended Micro Action: {micro_action}", extra={"user_id": self.user_id, "endpoint": "do_theme"})
831
  self.micro_actions.append(micro_action)
832
 
833
- return response
834
 
835
  def change_date(self, date):
836
  logger.info(f"Changing date from {self.conversations.state['date']} to {date}",
837
  extra={"user_id": self.user_id, "endpoint": "user_change_date"})
 
 
 
838
  self.conversations.state['date'] = date
839
 
840
  action = self.growth_plan.current()
841
 
 
 
 
 
 
 
 
842
  ## ADD POINT FOR CHANGE DATE
843
  if self.growth_plan.current()['day'] == 7:
844
  self.add_life_score_point(variable = self.get_current_goal(full=True).area, points_added = 5, notes = "Reaching Day 7")
@@ -856,31 +914,23 @@ class User:
856
 
857
  # The coaching theme conditions are hardcoded for now
858
  theme = action['coachingTheme']
859
- response = self.do_theme(theme, date, action['day'])
 
 
 
 
 
 
 
 
 
 
860
 
861
  # Move to the next action
862
  self.growth_plan.next()
863
 
864
- if self.reminders is not None and len(self.reminders):
865
- # remove all reminders which 'recurrence' is 'once' or 'action' is 'delete' or the date is < today
866
- # this is to ensure that only reminders with recurrence and future reminder are kept
867
- self.reminders = [reminder for reminder in self.reminders if not (reminder['action'] == 'delete' or (reminder['recurrence'] == 'once' and reminder['timestamp'] < pd.Timestamp.now()))]
868
- logger.info(f"Active Reminders: {self.reminders}", extra={"user_id": self.user_id, "endpoint": "user_change_date"})
869
-
870
- # response['reminders'] = all reminders which date is today (so all the reminders that BE has to queue today)
871
- # convert date to YYYY-MM-DD format
872
- date = pd.to_datetime(date).date()
873
- response['reminders'] = self.get_reminders(date)
874
- if len(response['reminders']) == 0:
875
- response['reminders'] = None
876
- logger.info(f"No reminders for today {date}", extra={"user_id": self.user_id, "endpoint": "user_change_date"})
877
- logger.info(f"Reminders on {date}: {response['reminders']}", extra={"user_id": self.user_id, "endpoint": "user_change_date"})
878
- else:
879
- response['reminders'] = None
880
-
881
-
882
  logger.info(f"Date Updated: {self.conversations.state['date']}", extra={"user_id": self.user_id, "endpoint": "user_change_date"})
883
- return response
884
 
885
  def update_user_info(self, new_info):
886
  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
 
 
451
  return None
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:
464
  g.status = status
 
519
  self.health_and_wellness_score = 0
520
  self.reminders = None
521
 
 
522
  def generate_user_interaction_guidelines(self, user_info, client):
523
  logger.info(f"Generating user interaction guidelines for user: {self.user_id}", extra={"user_id": self.user_id, "endpoint": "generate_user_interaction_guidelines"})
524
  # prompt = f"A 'profile' is a document containing rich insights on users for the purpose of \
 
575
  # must do current plan now
576
  action = self.growth_plan.current()
577
  logger.info(f"Current Action: {action}", extra={"user_id": self.user_id, "endpoint": "user_send_message"})
578
+ response, prompt = self.do_theme(action['coachingTheme'], self.conversations.state['date'], action['day'])
579
 
580
  # add response to ai message
581
+ self.add_ai_message("[hidden]" + prompt)
582
  self.add_ai_message(response['content'])
583
 
584
  # Move to the next action
 
791
 
792
  logger.info(f"Doing theme: {theme}", extra={"user_id": self.user_id, "endpoint": "do_theme"})
793
 
794
+ if self.reminders is not None and len(self.reminders):
795
+ logger.info(f"ALL Upcoming Reminders: {self.reminders}", extra={"user_id": self.user_id, "endpoint": "do_theme"})
796
+ reminders = list(filter(lambda x : x['recurrence'] == 'postponed', self.reminders))
797
+ logger.info(f"ALL Postponed Reminders: {reminders}", extra={"user_id": self.user_id, "endpoint": "do_theme"})
798
+ else:
799
+ reminders = []
800
+
801
+ # check if any of the posponed reminders have the date == date if yes, change the theme to "MICRO_ACTION_STATE"
802
+ if reminders:
803
+ for reminder in reminders:
804
+ if reminder['timestamp'].date() == pd.to_datetime(date).date():
805
+ logger.info(f"Reminder found for today ({pd.to_datetime(date).date()}): {reminder}", extra={"user_id": self.user_id, "endpoint": "do_theme"})
806
+ if day != 4:
807
+ theme = "MICRO_ACTION_STATE"
808
+ break
809
+ else:
810
+ logger.info(f"No reminders found for today ({pd.to_datetime(date).date()})", extra={"user_id": self.user_id, "endpoint": "do_theme"})
811
+
812
  if theme == "MOTIVATION_INSPIRATION_STATE":
813
  formatted_message = MOTIVATION_INSPIRATION_STATE.format(self.get_current_goal(), day, len(self.growth_plan.array), user_legendary_persona)
814
  elif theme == "PROGRESS_REFLECTION_STATE":
 
817
  challenge = self.challenges.pop(0)
818
  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) **"
819
  elif theme == "MICRO_ACTION_STATE":
820
+ reminder_message = "\n".join([f"{i+1}. {reminder}" for i, reminder in enumerate(reminders)]) if reminders else "User has no postponed micro-actions"
821
+
822
+ formatted_message = MICRO_ACTION_STATE.format(self.get_current_goal(), day, len(self.growth_plan.array), user_legendary_persona, reminder_message)
823
  if len(self.recommended_micro_actions):
824
  todays_micro_action = self.recommended_micro_actions.pop(0)
825
  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) **"
 
835
  elif theme == "EDUCATION_STATE":
836
  formatted_message = EDUCATION_STATE.format(self.get_current_goal(), day, len(self.growth_plan.array), user_legendary_persona)
837
  elif theme == "FOLLUP_ACTION_STATE":
838
+ reminder_message = "\n".join([f"{i+1}. {reminder}" for i, reminder in enumerate(reminders)]) if reminders else "User has no postponed micro-actions"
839
+ formatted_message = FOLLUP_ACTION_STATE.format(self.get_current_goal(), day, len(self.growth_plan.array), user_legendary_persona, knowledge, reminder_message)
840
 
841
  # prompt = f"""** It is a new day: {date} **
842
  # Additional System Instruction:
 
850
  # {formatted_message}
851
  # """
852
 
853
+ prompt = f"""** It is a new day: {date} ({day}) 10:00:00 **
854
  Additional System Instruction:
855
 
856
  To avoid a boring conversation, focus on giving more wisdom than questions by providing assertive guidance, valuable encouragement,
 
878
  logger.info(f"Recommended Micro Action: {micro_action}", extra={"user_id": self.user_id, "endpoint": "do_theme"})
879
  self.micro_actions.append(micro_action)
880
 
881
+ return response, prompt
882
 
883
  def change_date(self, date):
884
  logger.info(f"Changing date from {self.conversations.state['date']} to {date}",
885
  extra={"user_id": self.user_id, "endpoint": "user_change_date"})
886
+ # delete all hidden messages prom previous day
887
+ self.conversations.delete_hidden_messages()
888
+ # update the date in the state
889
  self.conversations.state['date'] = date
890
 
891
  action = self.growth_plan.current()
892
 
893
+ # remove stale reminders
894
+ if self.reminders is not None and len(self.reminders):
895
+ # remove all reminders which 'recurrence' is 'once' or 'action' is 'delete' or the date is < today
896
+ # this is to ensure that only reminders with recurrence and future reminder are kept
897
+ 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()))]
898
+ logger.info(f"Active Reminders: {self.reminders}", extra={"user_id": self.user_id, "endpoint": "user_change_date"})
899
+
900
  ## ADD POINT FOR CHANGE DATE
901
  if self.growth_plan.current()['day'] == 7:
902
  self.add_life_score_point(variable = self.get_current_goal(full=True).area, points_added = 5, notes = "Reaching Day 7")
 
914
 
915
  # The coaching theme conditions are hardcoded for now
916
  theme = action['coachingTheme']
917
+ response, prompt = self.do_theme(theme, date, action['day'])
918
+
919
+ # add today's reminders to response to schedule
920
+ # response['reminders'] = all reminders which date is today (so all the reminders that BE has to queue today)
921
+ # convert date to YYYY-MM-DD format
922
+ date = pd.to_datetime(date).date()
923
+ response['reminders'] = self.get_reminders(date)
924
+ if response['reminders'] is None or len(response['reminders']) == 0:
925
+ response['reminders'] = None
926
+ logger.info(f"No reminders for today {date}", extra={"user_id": self.user_id, "endpoint": "user_change_date"})
927
+ logger.info(f"Reminders on {date}: {response['reminders']}", extra={"user_id": self.user_id, "endpoint": "user_change_date"})
928
 
929
  # Move to the next action
930
  self.growth_plan.next()
931
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
932
  logger.info(f"Date Updated: {self.conversations.state['date']}", extra={"user_id": self.user_id, "endpoint": "user_change_date"})
933
+ return {'response': response, 'theme_prompt': '[hidden]'+prompt}
934
 
935
  def update_user_info(self, new_info):
936
  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__