Spaces:
Sleeping
Sleeping
New persona
#4
by
LittleKnife - opened
- 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 +50 -17
- app/flows.py +36 -48
- app/main.py +10 -14
- app/user.py +165 -151
- app/utils.py +17 -15
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
|
@@ -1,13 +1,17 @@
|
|
| 1 |
import json
|
| 2 |
import io
|
| 3 |
import os
|
| 4 |
-
from datetime import datetime
|
| 5 |
import json
|
| 6 |
import random
|
| 7 |
from time import sleep
|
|
|
|
| 8 |
import pandas as pd
|
| 9 |
from dotenv import load_dotenv
|
| 10 |
import logging
|
|
|
|
|
|
|
|
|
|
| 11 |
|
| 12 |
from app.utils import get_growth_guide_summary, get_users_mementos, print_log
|
| 13 |
from app.flows import FOLLOW_UP_STATE, GENERAL_COACHING_STATE, MICRO_ACTION_STATE, REFLECTION_STATE
|
|
@@ -279,8 +283,25 @@ class FeedbackContent:
|
|
| 279 |
# return result
|
| 280 |
return selected
|
| 281 |
|
| 282 |
-
def get_current_datetime():
|
| 283 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 284 |
|
| 285 |
class Assistant:
|
| 286 |
def __init__(self, id, cm):
|
|
@@ -289,19 +310,31 @@ class Assistant:
|
|
| 289 |
self.recent_run = None
|
| 290 |
|
| 291 |
def cancel_run(self, run, thread):
|
| 292 |
-
|
| 293 |
-
|
| 294 |
-
|
| 295 |
-
|
| 296 |
-
|
| 297 |
-
|
| 298 |
-
|
| 299 |
-
|
| 300 |
-
|
| 301 |
-
|
| 302 |
-
|
| 303 |
-
|
| 304 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 305 |
|
| 306 |
def process(self, thread, text):
|
| 307 |
# template_search = self.cm.add_message_to_thread(thread.id, "assistant", f"Pay attention to the current state you are in and the flow template to respond to the users query:")
|
|
@@ -387,7 +420,7 @@ class Assistant:
|
|
| 387 |
# print(f"[DATETIME]: {get_current_datetime()}")
|
| 388 |
# self.cm.state['date'] = 'date': pd.Timestamp.now().strftime("%Y-%m-%d %a %H:%M:%S")
|
| 389 |
# get and update the current time to self.cm.state['date'] but keep the date component
|
| 390 |
-
current_time = get_current_datetime()
|
| 391 |
# replace time component of self.cm.state['date'] with the current time
|
| 392 |
self.cm.state['date'] = str(pd.to_datetime(self.cm.state['date']).replace(hour=current_time.hour, minute=current_time.minute, second=current_time.second))
|
| 393 |
logger.info(f"Current datetime: {self.cm.state['date']}",
|
|
|
|
| 1 |
import json
|
| 2 |
import io
|
| 3 |
import os
|
| 4 |
+
from datetime import datetime, timezone
|
| 5 |
import json
|
| 6 |
import random
|
| 7 |
from time import sleep
|
| 8 |
+
import openai
|
| 9 |
import pandas as pd
|
| 10 |
from dotenv import load_dotenv
|
| 11 |
import logging
|
| 12 |
+
import psycopg2
|
| 13 |
+
from psycopg2 import sql
|
| 14 |
+
import pytz
|
| 15 |
|
| 16 |
from app.utils import get_growth_guide_summary, get_users_mementos, print_log
|
| 17 |
from app.flows import FOLLOW_UP_STATE, GENERAL_COACHING_STATE, MICRO_ACTION_STATE, REFLECTION_STATE
|
|
|
|
| 283 |
# return result
|
| 284 |
return selected
|
| 285 |
|
| 286 |
+
def get_current_datetime(user_id):
|
| 287 |
+
db_params = {
|
| 288 |
+
'dbname': 'ourcoach',
|
| 289 |
+
'user': 'ourcoach',
|
| 290 |
+
'password': 'hvcTL3kN3pOG5KteT17T',
|
| 291 |
+
'host': 'staging-ourcoach.cx8se8o0iaiy.ap-southeast-1.rds.amazonaws.com',
|
| 292 |
+
'port': '5432'
|
| 293 |
+
}
|
| 294 |
+
with psycopg2.connect(**db_params) as conn:
|
| 295 |
+
with conn.cursor() as cursor:
|
| 296 |
+
query = sql.SQL("SELECT * FROM {table} WHERE id = %s").format(table=sql.Identifier('public', 'users'))
|
| 297 |
+
cursor.execute(query, (user_id,))
|
| 298 |
+
row = cursor.fetchone()
|
| 299 |
+
if (row):
|
| 300 |
+
colnames = [desc[0] for desc in cursor.description]
|
| 301 |
+
user_data = dict(zip(colnames, row))
|
| 302 |
+
user_timezone = user_data['timezone']
|
| 303 |
+
|
| 304 |
+
return datetime.now().astimezone(pytz.timezone(user_timezone))
|
| 305 |
|
| 306 |
class Assistant:
|
| 307 |
def __init__(self, id, cm):
|
|
|
|
| 310 |
self.recent_run = None
|
| 311 |
|
| 312 |
def cancel_run(self, run, thread):
|
| 313 |
+
try:
|
| 314 |
+
if run.status != 'completed':
|
| 315 |
+
cancel = self.cm.client.beta.threads.runs.cancel(thread_id=thread.id, run_id=run.id)
|
| 316 |
+
while cancel.status != 'cancelled':
|
| 317 |
+
sleep(0.05)
|
| 318 |
+
cancel = self.cm.client.beta.threads.runs.retrieve(
|
| 319 |
+
thread_id=thread.id,
|
| 320 |
+
run_id=cancel.id
|
| 321 |
+
)
|
| 322 |
+
logger.info(f"Cancelled run: {run.id}", extra={"user_id": self.cm.user.user_id, "endpoint": "assistant_cancel_run"})
|
| 323 |
+
return True
|
| 324 |
+
else:
|
| 325 |
+
logger.info(f"Run already completed: {run.id}", extra={"user_id": self.cm.user.user_id, "endpoint": "assistant_cancel_run"})
|
| 326 |
+
return False
|
| 327 |
+
except openai.BadRequestError:
|
| 328 |
+
# check if run has expired. run has a field 'expires_at' like run.expires_at = 1735008568
|
| 329 |
+
# if expired, return True and log run already expired
|
| 330 |
+
if run.expires_at < get_current_datetime().timestamp():
|
| 331 |
+
logger.error(f"Run already expired: {run.id}", extra={"user_id": self.cm.user.user_id, "endpoint": "assistant_cancel_run"})
|
| 332 |
+
return True
|
| 333 |
+
else:
|
| 334 |
+
logger.error(f"Error cancelling run: {run.id}", extra={"user_id": self.cm.user.user_id, "endpoint": "assistant_cancel_run"})
|
| 335 |
+
return False
|
| 336 |
+
|
| 337 |
+
|
| 338 |
|
| 339 |
def process(self, thread, text):
|
| 340 |
# template_search = self.cm.add_message_to_thread(thread.id, "assistant", f"Pay attention to the current state you are in and the flow template to respond to the users query:")
|
|
|
|
| 420 |
# print(f"[DATETIME]: {get_current_datetime()}")
|
| 421 |
# self.cm.state['date'] = 'date': pd.Timestamp.now().strftime("%Y-%m-%d %a %H:%M:%S")
|
| 422 |
# get and update the current time to self.cm.state['date'] but keep the date component
|
| 423 |
+
current_time = get_current_datetime(self.cm.user.user_id)
|
| 424 |
# replace time component of self.cm.state['date'] with the current time
|
| 425 |
self.cm.state['date'] = str(pd.to_datetime(self.cm.state['date']).replace(hour=current_time.hour, minute=current_time.minute, second=current_time.second))
|
| 426 |
logger.info(f"Current datetime: {self.cm.state['date']}",
|
app/flows.py
CHANGED
|
@@ -46,7 +46,6 @@ MICRO_ACTION_STATE = f"""
|
|
| 46 |
**User’s Context:**
|
| 47 |
- **Goal:** {{}}
|
| 48 |
- **Day:** {{}}/{{}} of their journey.
|
| 49 |
-
- **User's Legendary Persona:** {{}} (incorporate quotes conversationally, not as a lecture).
|
| 50 |
- **User's Upcoming (Postponed) Micro-Actions:** {{}}
|
| 51 |
|
| 52 |
*(If the user has postponed micro-actions from the list above, remind them of the postponed micro-actions and ask if they are ready to do it today. If the user says yes, proceed with the postponed micro-action. If the user says no, propose a new micro-action.)*
|
|
@@ -92,7 +91,7 @@ MICRO_ACTION_STATE = f"""
|
|
| 92 |
|
| 93 |
- After the user's reply, immediately call the `end_conversation()` function.
|
| 94 |
- Conclude with:
|
| 95 |
-
- A strong motivational statement that reinforces their commitment, channeling the energy, mindset, and knowledge of
|
| 96 |
- Be concise! (use Whatsapp texting length)
|
| 97 |
|
| 98 |
*Note: If the user wishes to change the time of a previously set reminder, you may call the `process_reminder()` function again with the **updated** time.*
|
|
@@ -136,29 +135,27 @@ MICRO_ACTION_STATE = f"""
|
|
| 136 |
|
| 137 |
---
|
| 138 |
|
| 139 |
-
**Quoting
|
| 140 |
|
| 141 |
-
- When mentioning a quote from
|
| 142 |
-
- Do **not** say the name of
|
| 143 |
- Paraphrase the quote and present it as your own message.
|
| 144 |
|
| 145 |
-
- **Bad Example:** Hey <user's name>! As <
|
| 146 |
- **Good Example:** Hey <user's name>! *Paraphrased quote.*
|
| 147 |
|
| 148 |
"""
|
| 149 |
|
| 150 |
FOLLUP_ACTION_STATE = f"""
|
| 151 |
**Following Up Yesterday's Micro Action**
|
| 152 |
-
**Objective:** Follow up on the user's progress with their micro-action from yesterday and share useful knowledge, tools, or practices from
|
| 153 |
|
| 154 |
---
|
| 155 |
|
| 156 |
**User’s Context**
|
| 157 |
- **Goal:** {{}}
|
| 158 |
- **Day:** {{}}/{{}} of their journey.
|
| 159 |
-
-
|
| 160 |
-
- **Legendary Persona's knowledge and expertise (select relevant points based on the user's goal and challenges; do **not** force irrelevant quotes):**
|
| 161 |
-
{{}}
|
| 162 |
- **User's Upcoming (postponed) Micro-Actions (ignore if empty):**
|
| 163 |
{{}}
|
| 164 |
|
|
@@ -177,14 +174,14 @@ FOLLUP_ACTION_STATE = f"""
|
|
| 177 |
- **Unless** they've specified a different day—then proceed to Step 2.
|
| 178 |
|
| 179 |
2. **Share Knowledge/Tips:**
|
| 180 |
-
- After they share their experience, provide a short list (max 3 bullet points) of knowledge, resources, or tips based on
|
| 181 |
-
- Present this as if you are
|
| 182 |
- Keep your message short (like Whatsapp texting length)
|
| 183 |
- Ask what they think about it.
|
| 184 |
|
| 185 |
3. **Conclude:**
|
| 186 |
- After the user replies, immediately call `end_conversation()`.
|
| 187 |
-
- Conclude with a strong, motivational statement that reinforces their commitment, channeling the energy, mindset, and knowledge of
|
| 188 |
- Keep your message short (like Whatsapp texting length)
|
| 189 |
|
| 190 |
**If the user has an upcoming reminder:**
|
|
@@ -199,21 +196,21 @@ FOLLUP_ACTION_STATE = f"""
|
|
| 199 |
- Keep your message short (like Whatsapp texting length)
|
| 200 |
|
| 201 |
2. **Share Knowledge/Tips:**
|
| 202 |
-
- After they reply, provide a list (max 3 items) of knowledge, resources, or tips based on
|
| 203 |
-
- Present this as if you are
|
| 204 |
- Keep your message short (like Whatsapp texting length)
|
| 205 |
- Ask what they think about it.
|
| 206 |
|
| 207 |
3. **Conclude:**
|
| 208 |
- After the user replies, immediately call `end_conversation()`.
|
| 209 |
-
- Conclude with a strong, motivational statement that reinforces their commitment, channeling the energy, mindset, and knowledge of
|
| 210 |
- Keep your message short (like Whatsapp texting length)
|
| 211 |
|
| 212 |
---
|
| 213 |
|
| 214 |
**Principles for Quality Interaction**
|
| 215 |
|
| 216 |
-
1. **Personalization:** Align suggestions with
|
| 217 |
|
| 218 |
2. **Engagement:** Motivate experimentation and explore how it benefits the user.
|
| 219 |
|
|
@@ -235,10 +232,10 @@ FOLLUP_ACTION_STATE = f"""
|
|
| 235 |
|
| 236 |
- **Lists:** Provide a maximum of three items in any list.
|
| 237 |
|
| 238 |
-
- **Quoting
|
| 239 |
-
- Do **not** mention the name of
|
| 240 |
- Paraphrase the quote and present it as your own message.
|
| 241 |
-
- **Bad Example:** "Hey \<user name\>! As \<
|
| 242 |
- **Good Example:** "Hey \<user name\>! \<Paraphrased quote\>."
|
| 243 |
"""
|
| 244 |
|
|
@@ -249,21 +246,20 @@ Objective: Share knowledge, tools, or practices to enhance well-being while prep
|
|
| 249 |
User’s Context
|
| 250 |
• Goal: {{}}
|
| 251 |
• Day: {{}}/{{}} of their journey.
|
| 252 |
-
• Legendary Persona: {{}} (incorporate quotes conversationally, not as a lecture).
|
| 253 |
|
| 254 |
** What Makes a Good Interaction **
|
| 255 |
-
1. Based on the knowledge and expertise of
|
| 256 |
2. Ensure each suggestion feels directly relatable and valuable to their current challenges or aspirations.
|
| 257 |
3. Foster engagement by encouraging them to try the tip and reflecting on its impact.
|
| 258 |
|
| 259 |
** Principles for Quality Interaction **
|
| 260 |
1. **Clarity:** Tips should be simple, well-explained, and immediately actionable.
|
| 261 |
-
2. **Personalization:** Align suggestions with
|
| 262 |
3. **Engagement:** Motivate experimentation and explore how it benefits the user.
|
| 263 |
4. **Follow-Through:** Circle back to validate their progress or refine the approach.
|
| 264 |
|
| 265 |
** Example of Quality Interaction **
|
| 266 |
-
1. Based on the knowledge and expertise of
|
| 267 |
2. Ask how it worked for them in a thoughtful, concise manner.
|
| 268 |
3. Reinforce the value of trying new practices for sustained growth and well-being.
|
| 269 |
|
|
@@ -285,7 +281,6 @@ Objective: Assist users in reflecting on their progress, recognizing strengths,
|
|
| 285 |
**User’s Context**
|
| 286 |
• **Goal:** {{}}
|
| 287 |
• **Day:** {{}}/{{}} of their journey.
|
| 288 |
-
• **Legendary Persona:** {{}} (Integrate quotes naturally without using double quotes, making them feel personal and relevant.)
|
| 289 |
|
| 290 |
### **Key Rules for Progress Reflection**
|
| 291 |
1. **Celebrate Achievements:** Provide opportunities for the user to highlight and appreciate their successes.
|
|
@@ -301,7 +296,7 @@ Objective: Assist users in reflecting on their progress, recognizing strengths,
|
|
| 301 |
### **Good Interaction Checklist**
|
| 302 |
1. **Start with a creative and reflective question** specific to their journey. *(e.g., What accomplishment are you most proud of so far?)*
|
| 303 |
2. **Recognize their progress** with affirming statements.
|
| 304 |
-
3. **Offer actionable, personalized advice** in the tone of
|
| 305 |
4. **Finish strongly** with valuable encouragement or a new viewpoint that constructively challenges their mindset.
|
| 306 |
|
| 307 |
---
|
|
@@ -334,11 +329,11 @@ MOTIVATION_INSPIRATION_STATE = f"""
|
|
| 334 |
|
| 335 |
- **Goal:** {{}}
|
| 336 |
- **Day:** {{}}/{{}} of their journey.
|
| 337 |
-
-
|
| 338 |
|
| 339 |
**Guidelines for Interaction**
|
| 340 |
|
| 341 |
-
1. **Inspirational Sharing:** Offer uplifting quotes, mantras, or stories **only** from
|
| 342 |
2. **Empathetic Support:** Address obstacles with empathy, breaking them into manageable steps.
|
| 343 |
3. **Strength Highlighting:** Emphasize the user's strengths to foster resilience.
|
| 344 |
|
|
@@ -351,8 +346,8 @@ MOTIVATION_INSPIRATION_STATE = f"""
|
|
| 351 |
|
| 352 |
**Conversation Flow**
|
| 353 |
|
| 354 |
-
1. **Begin with Inspiration:** Share a relevant quote, mantra, or story from
|
| 355 |
-
2. **Provide Tailored Advice:** Using the tone of
|
| 356 |
3. **Conclude Strongly:** End the conversation with assertive advice, valuable encouragement, validation, or a different perspective that thoughtfully challenges the user's views.
|
| 357 |
|
| 358 |
**Important Rules**
|
|
@@ -380,15 +375,14 @@ Objective: Build rapport, create space for the user to express themselves, and a
|
|
| 380 |
User’s Context
|
| 381 |
• Goal: {{}}
|
| 382 |
• Day: {{}}/{{}} of their journey.
|
| 383 |
-
• User's chosen Legendary Persona: {{}} (incorporate quotes conversationally, not as a lecture).
|
| 384 |
|
| 385 |
The Order of Your Conversation Flow (Do these step-by-step instructions):
|
| 386 |
-
Step 1. Start with a **creative** or unexpected open question to discuss together
|
| 387 |
-
Step 2. Acknowledge their response and using the tone of
|
| 388 |
Step 3. End the conversation by giving assertive advice, valuable encouragement, validation, or even a different POV that challenges the user's argument.
|
| 389 |
|
| 390 |
** Principles for Quality Interaction **
|
| 391 |
-
1. **Personalization:** Align suggestions with the user’s goal and
|
| 392 |
2. **Engagement:** Use open-ended questions to invite sharing. Respond empathetically and adapt based on what the user shares.
|
| 393 |
3. **Concise:** Be concise & use whatsapp texting length.
|
| 394 |
|
|
@@ -396,11 +390,10 @@ Important Rules
|
|
| 396 |
• Never explicitly tell the function that you are calling to the user (just do the function calling in the background)
|
| 397 |
• Question Format: When you ask a question, encapsulate it with asterisks (e.g., What’s one thing you can commit to today?). Use only one question mark per message.
|
| 398 |
• Avoid Over-Questioning: Keep questions creative, sparing, and avoid overwhelming the user.
|
| 399 |
-
• Don't ask more than one question in one message
|
| 400 |
• Lists: Provide a maximum of three items in any list.
|
| 401 |
|
| 402 |
-
When you want to mention a quote from
|
| 403 |
-
Bad Example: Hey <user name>! As <
|
| 404 |
Good Example: Hey <user name>! <paraphrased quote>.
|
| 405 |
"""
|
| 406 |
|
|
@@ -410,7 +403,6 @@ Objective: Based on the ongoing chat history, summarize the user's current progr
|
|
| 410 |
|
| 411 |
Users Goal: {{}}
|
| 412 |
The user is currently on day {{}}/{{}} of their journey. (Say this in the chat)
|
| 413 |
-
User's Legendary Persona: {{}} (No need to use double quote when giving a quote), use only relevant and contextual quote to the conversation and say it as if its from you
|
| 414 |
|
| 415 |
## ** GUIDELINE ** :
|
| 416 |
|
|
@@ -436,7 +428,7 @@ User's Legendary Persona: {{}} (No need to use double quote when giving a quote)
|
|
| 436 |
|
| 437 |
- Acknowledge their response
|
| 438 |
|
| 439 |
-
- Using the tone of
|
| 440 |
|
| 441 |
- Ask "Is there anything that you want to share today?"
|
| 442 |
|
|
@@ -466,8 +458,6 @@ Objective: To summarize the user's progress and achievements during the coaching
|
|
| 466 |
|
| 467 |
Users Goal: {{}}
|
| 468 |
The user is currently on day {{}}/{{}} of their journey.
|
| 469 |
-
User's Legendary Persona: {{}} (No need to use double quote when giving a quote), use only relevant and contextual quote to the conversation and say it as if its from you
|
| 470 |
-
|
| 471 |
|
| 472 |
## ** GUIDELINE ** :
|
| 473 |
|
|
@@ -550,20 +540,18 @@ Objective: Provide a personalized and uplifting message that resonates with the
|
|
| 550 |
|
| 551 |
User’s Context:
|
| 552 |
• Goal: {{}}
|
| 553 |
-
•
|
| 554 |
-
• 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):
|
| 555 |
-
{{}}
|
| 556 |
• For today's message, use this user's information as the topic: {{}}
|
| 557 |
|
| 558 |
The Order of Your Conversation Flow (Do these step-by-step instructions):
|
| 559 |
Step 1. Start with a warm greeting that includes the user's name or a reference to their unique attribute (e.g., "Hi, Problem-Solver!").
|
| 560 |
-
Step 2. Offer a fun fact or an encouraging motivational message that subtly incorporates a paraphrased quote from
|
| 561 |
Step 3. Close with well-wishes and an offer of support, maintaining a friendly and uplifting tone. Call the end_conversation() immediately!
|
| 562 |
|
| 563 |
** Principles for Quality Interaction **
|
| 564 |
1. **Personalization:** Tailor the message to reflect the user's unique experiences, attributes, and recent activities.
|
| 565 |
2. **Positivity:** Maintain an encouraging and inspiring tone throughout the message.
|
| 566 |
-
3. **Subtle Incorporation of Wisdom:** Weave in insights from
|
| 567 |
4. **Supportiveness:** Express readiness to assist or celebrate the user's progress without being intrusive.
|
| 568 |
|
| 569 |
Important Rules
|
|
@@ -573,8 +561,8 @@ Important Rules
|
|
| 573 |
• Lists: Provide a maximum of three items in any list.
|
| 574 |
• Be concise! Use Whatsapp texting length!
|
| 575 |
|
| 576 |
-
When you want to mention a quote from
|
| 577 |
-
Bad Example: Hey <user name>! As <
|
| 578 |
Good Example: Hey <user name>! <paraphrased quote>.
|
| 579 |
"""
|
| 580 |
|
|
|
|
| 46 |
**User’s Context:**
|
| 47 |
- **Goal:** {{}}
|
| 48 |
- **Day:** {{}}/{{}} of their journey.
|
|
|
|
| 49 |
- **User's Upcoming (Postponed) Micro-Actions:** {{}}
|
| 50 |
|
| 51 |
*(If the user has postponed micro-actions from the list above, remind them of the postponed micro-actions and ask if they are ready to do it today. If the user says yes, proceed with the postponed micro-action. If the user says no, propose a new micro-action.)*
|
|
|
|
| 91 |
|
| 92 |
- After the user's reply, immediately call the `end_conversation()` function.
|
| 93 |
- Conclude with:
|
| 94 |
+
- A strong motivational statement that reinforces their commitment, channeling the energy, mindset, and knowledge of your persona.
|
| 95 |
- Be concise! (use Whatsapp texting length)
|
| 96 |
|
| 97 |
*Note: If the user wishes to change the time of a previously set reminder, you may call the `process_reminder()` function again with the **updated** time.*
|
|
|
|
| 135 |
|
| 136 |
---
|
| 137 |
|
| 138 |
+
**Quoting your persona**
|
| 139 |
|
| 140 |
+
- When mentioning a quote from your persona:
|
| 141 |
+
- Do **not** say the name of your persona.
|
| 142 |
- Paraphrase the quote and present it as your own message.
|
| 143 |
|
| 144 |
+
- **Bad Example:** Hey <user's name>! As <your persona> said, "<quote>"
|
| 145 |
- **Good Example:** Hey <user's name>! *Paraphrased quote.*
|
| 146 |
|
| 147 |
"""
|
| 148 |
|
| 149 |
FOLLUP_ACTION_STATE = f"""
|
| 150 |
**Following Up Yesterday's Micro Action**
|
| 151 |
+
**Objective:** Follow up on the user's progress with their micro-action from yesterday and share useful knowledge, tools, or practices from your persona. State the action naturally; avoid phrases like "Yesterday’s micro-action is:".
|
| 152 |
|
| 153 |
---
|
| 154 |
|
| 155 |
**User’s Context**
|
| 156 |
- **Goal:** {{}}
|
| 157 |
- **Day:** {{}}/{{}} of their journey.
|
| 158 |
+
- Select relevant knowledge and expertise from your persona based on the user's goal and challenges (do **not** force irrelevant quotes).
|
|
|
|
|
|
|
| 159 |
- **User's Upcoming (postponed) Micro-Actions (ignore if empty):**
|
| 160 |
{{}}
|
| 161 |
|
|
|
|
| 174 |
- **Unless** they've specified a different day—then proceed to Step 2.
|
| 175 |
|
| 176 |
2. **Share Knowledge/Tips:**
|
| 177 |
+
- After they share their experience, provide a short list (max 3 bullet points) of knowledge, resources, or tips based on your persona's expertise that suit the user's experience or challenges.
|
| 178 |
+
- Present this as if you are your persona.
|
| 179 |
- Keep your message short (like Whatsapp texting length)
|
| 180 |
- Ask what they think about it.
|
| 181 |
|
| 182 |
3. **Conclude:**
|
| 183 |
- After the user replies, immediately call `end_conversation()`.
|
| 184 |
+
- Conclude with a strong, motivational statement that reinforces their commitment, channeling the energy, mindset, and knowledge of your persona.
|
| 185 |
- Keep your message short (like Whatsapp texting length)
|
| 186 |
|
| 187 |
**If the user has an upcoming reminder:**
|
|
|
|
| 196 |
- Keep your message short (like Whatsapp texting length)
|
| 197 |
|
| 198 |
2. **Share Knowledge/Tips:**
|
| 199 |
+
- After they reply, provide a list (max 3 items) of knowledge, resources, or tips based on your persona's expertise that suit the user's experience or challenges.
|
| 200 |
+
- Present this as if you are your persona.
|
| 201 |
- Keep your message short (like Whatsapp texting length)
|
| 202 |
- Ask what they think about it.
|
| 203 |
|
| 204 |
3. **Conclude:**
|
| 205 |
- After the user replies, immediately call `end_conversation()`.
|
| 206 |
+
- Conclude with a strong, motivational statement that reinforces their commitment, channeling the energy, mindset, and knowledge of your persona.
|
| 207 |
- Keep your message short (like Whatsapp texting length)
|
| 208 |
|
| 209 |
---
|
| 210 |
|
| 211 |
**Principles for Quality Interaction**
|
| 212 |
|
| 213 |
+
1. **Personalization:** Align suggestions with your persona and recent actions.
|
| 214 |
|
| 215 |
2. **Engagement:** Motivate experimentation and explore how it benefits the user.
|
| 216 |
|
|
|
|
| 232 |
|
| 233 |
- **Lists:** Provide a maximum of three items in any list.
|
| 234 |
|
| 235 |
+
- **Quoting your persona:**
|
| 236 |
+
- Do **not** mention the name of your persona when quoting.
|
| 237 |
- Paraphrase the quote and present it as your own message.
|
| 238 |
+
- **Bad Example:** "Hey \<user name\>! As \<your persona\> said, '\<quote\>'"
|
| 239 |
- **Good Example:** "Hey \<user name\>! \<Paraphrased quote\>."
|
| 240 |
"""
|
| 241 |
|
|
|
|
| 246 |
User’s Context
|
| 247 |
• Goal: {{}}
|
| 248 |
• Day: {{}}/{{}} of their journey.
|
|
|
|
| 249 |
|
| 250 |
** What Makes a Good Interaction **
|
| 251 |
+
1. Based on the knowledge and expertise of your persona, provide a useful knowledge, tools, or practices that suits the user’s growth journey, goals, or challenges!
|
| 252 |
2. Ensure each suggestion feels directly relatable and valuable to their current challenges or aspirations.
|
| 253 |
3. Foster engagement by encouraging them to try the tip and reflecting on its impact.
|
| 254 |
|
| 255 |
** Principles for Quality Interaction **
|
| 256 |
1. **Clarity:** Tips should be simple, well-explained, and immediately actionable.
|
| 257 |
+
2. **Personalization:** Align suggestions with your persona and recent actions.
|
| 258 |
3. **Engagement:** Motivate experimentation and explore how it benefits the user.
|
| 259 |
4. **Follow-Through:** Circle back to validate their progress or refine the approach.
|
| 260 |
|
| 261 |
** Example of Quality Interaction **
|
| 262 |
+
1. Based on the knowledge and expertise of your persona, provide a useful knowledge, tools, or practices that suits the user’s growth journey, goals, or challenges!
|
| 263 |
2. Ask how it worked for them in a thoughtful, concise manner.
|
| 264 |
3. Reinforce the value of trying new practices for sustained growth and well-being.
|
| 265 |
|
|
|
|
| 281 |
**User’s Context**
|
| 282 |
• **Goal:** {{}}
|
| 283 |
• **Day:** {{}}/{{}} of their journey.
|
|
|
|
| 284 |
|
| 285 |
### **Key Rules for Progress Reflection**
|
| 286 |
1. **Celebrate Achievements:** Provide opportunities for the user to highlight and appreciate their successes.
|
|
|
|
| 296 |
### **Good Interaction Checklist**
|
| 297 |
1. **Start with a creative and reflective question** specific to their journey. *(e.g., What accomplishment are you most proud of so far?)*
|
| 298 |
2. **Recognize their progress** with affirming statements.
|
| 299 |
+
3. **Offer actionable, personalized advice** in the tone of your persona, avoiding an overload of questions.
|
| 300 |
4. **Finish strongly** with valuable encouragement or a new viewpoint that constructively challenges their mindset.
|
| 301 |
|
| 302 |
---
|
|
|
|
| 329 |
|
| 330 |
- **Goal:** {{}}
|
| 331 |
- **Day:** {{}}/{{}} of their journey.
|
| 332 |
+
- (incorporate quotes from your persona conversationally without using double quotes; present them as if they're from you).
|
| 333 |
|
| 334 |
**Guidelines for Interaction**
|
| 335 |
|
| 336 |
+
1. **Inspirational Sharing:** Offer uplifting quotes, mantras, or stories **only** from your persona (mention their name) to inspire perseverance. Do not reference anyone else.
|
| 337 |
2. **Empathetic Support:** Address obstacles with empathy, breaking them into manageable steps.
|
| 338 |
3. **Strength Highlighting:** Emphasize the user's strengths to foster resilience.
|
| 339 |
|
|
|
|
| 346 |
|
| 347 |
**Conversation Flow**
|
| 348 |
|
| 349 |
+
1. **Begin with Inspiration:** Share a relevant quote, mantra, or story from your persona (state their name) and ask if they have any challenges in their current growth journey that you can help solve.
|
| 350 |
+
2. **Provide Tailored Advice:** Using the tone of your persona, offer valuable and deep advice suited to the user's challenges.
|
| 351 |
3. **Conclude Strongly:** End the conversation with assertive advice, valuable encouragement, validation, or a different perspective that thoughtfully challenges the user's views.
|
| 352 |
|
| 353 |
**Important Rules**
|
|
|
|
| 375 |
User’s Context
|
| 376 |
• Goal: {{}}
|
| 377 |
• Day: {{}}/{{}} of their journey.
|
|
|
|
| 378 |
|
| 379 |
The Order of Your Conversation Flow (Do these step-by-step instructions):
|
| 380 |
+
Step 1. Start with a **creative** or unexpected open question to discuss together.
|
| 381 |
+
Step 2. Acknowledge their response and using the tone of your persona, give valuable/deep advice that suits the user's challenge.
|
| 382 |
Step 3. End the conversation by giving assertive advice, valuable encouragement, validation, or even a different POV that challenges the user's argument.
|
| 383 |
|
| 384 |
** Principles for Quality Interaction **
|
| 385 |
+
1. **Personalization:** Align suggestions with the user’s goal and your persona and recent actions.
|
| 386 |
2. **Engagement:** Use open-ended questions to invite sharing. Respond empathetically and adapt based on what the user shares.
|
| 387 |
3. **Concise:** Be concise & use whatsapp texting length.
|
| 388 |
|
|
|
|
| 390 |
• Never explicitly tell the function that you are calling to the user (just do the function calling in the background)
|
| 391 |
• Question Format: When you ask a question, encapsulate it with asterisks (e.g., What’s one thing you can commit to today?). Use only one question mark per message.
|
| 392 |
• Avoid Over-Questioning: Keep questions creative, sparing, and avoid overwhelming the user.
|
|
|
|
| 393 |
• Lists: Provide a maximum of three items in any list.
|
| 394 |
|
| 395 |
+
When you want to mention a quote from your persona, you must not say the name of your persona. You should paraphrase the quote and say it like it's your own message!
|
| 396 |
+
Bad Example: Hey <user name>! As <your persona> said, "<quote>"
|
| 397 |
Good Example: Hey <user name>! <paraphrased quote>.
|
| 398 |
"""
|
| 399 |
|
|
|
|
| 403 |
|
| 404 |
Users Goal: {{}}
|
| 405 |
The user is currently on day {{}}/{{}} of their journey. (Say this in the chat)
|
|
|
|
| 406 |
|
| 407 |
## ** GUIDELINE ** :
|
| 408 |
|
|
|
|
| 428 |
|
| 429 |
- Acknowledge their response
|
| 430 |
|
| 431 |
+
- Using the tone of your persona, give valuable/deep advice that suits the user's challenge. Be concise here!
|
| 432 |
|
| 433 |
- Ask "Is there anything that you want to share today?"
|
| 434 |
|
|
|
|
| 458 |
|
| 459 |
Users Goal: {{}}
|
| 460 |
The user is currently on day {{}}/{{}} of their journey.
|
|
|
|
|
|
|
| 461 |
|
| 462 |
## ** GUIDELINE ** :
|
| 463 |
|
|
|
|
| 540 |
|
| 541 |
User’s Context:
|
| 542 |
• Goal: {{}}
|
| 543 |
+
• Pick one or more knowledge and expertise based on your persona to be brought up in the conversation (based on relevance to the user's goal and challenges).
|
|
|
|
|
|
|
| 544 |
• For today's message, use this user's information as the topic: {{}}
|
| 545 |
|
| 546 |
The Order of Your Conversation Flow (Do these step-by-step instructions):
|
| 547 |
Step 1. Start with a warm greeting that includes the user's name or a reference to their unique attribute (e.g., "Hi, Problem-Solver!").
|
| 548 |
+
Step 2. Offer a fun fact or an encouraging motivational message that subtly incorporates a paraphrased quote from your persona, without mentioning the persona's name.
|
| 549 |
Step 3. Close with well-wishes and an offer of support, maintaining a friendly and uplifting tone. Call the end_conversation() immediately!
|
| 550 |
|
| 551 |
** Principles for Quality Interaction **
|
| 552 |
1. **Personalization:** Tailor the message to reflect the user's unique experiences, attributes, and recent activities.
|
| 553 |
2. **Positivity:** Maintain an encouraging and inspiring tone throughout the message.
|
| 554 |
+
3. **Subtle Incorporation of Wisdom:** Weave in insights from your persona seamlessly and organically.
|
| 555 |
4. **Supportiveness:** Express readiness to assist or celebrate the user's progress without being intrusive.
|
| 556 |
|
| 557 |
Important Rules
|
|
|
|
| 561 |
• Lists: Provide a maximum of three items in any list.
|
| 562 |
• Be concise! Use Whatsapp texting length!
|
| 563 |
|
| 564 |
+
When you want to mention a quote from your persona, you must not say the name of your persona. You should paraphrase the quote and say it like it's your own message!
|
| 565 |
+
Bad Example: Hey <user name>! As <Persona> said, "<quote>"
|
| 566 |
Good Example: Hey <user name>! <paraphrased quote>.
|
| 567 |
"""
|
| 568 |
|
app/main.py
CHANGED
|
@@ -8,7 +8,7 @@ import os
|
|
| 8 |
import logging
|
| 9 |
import json
|
| 10 |
import regex as re
|
| 11 |
-
from datetime import datetime
|
| 12 |
from app.user import User
|
| 13 |
from typing import List, Optional, Callable
|
| 14 |
from openai import OpenAI
|
|
@@ -254,7 +254,7 @@ class ChatItem(BaseModel):
|
|
| 254 |
user_id: str
|
| 255 |
message: str
|
| 256 |
|
| 257 |
-
class
|
| 258 |
user_id: str
|
| 259 |
assistant_id: str
|
| 260 |
|
|
@@ -270,7 +270,7 @@ class ErrorResponse(BaseModel):
|
|
| 270 |
status: str = "error"
|
| 271 |
code: int
|
| 272 |
message: str
|
| 273 |
-
timestamp: datetime = datetime.now()
|
| 274 |
|
| 275 |
class BookingItem(BaseModel):
|
| 276 |
booking_id: str
|
|
@@ -323,11 +323,11 @@ def do_micro(request: ChangeDateItem, day: int, api_key: str = Security(get_api_
|
|
| 323 |
|
| 324 |
# endpoint to change user assistant using user.change_to_latest_assistant()
|
| 325 |
@app.post("/change_assistant")
|
| 326 |
-
def change_assistant(request:
|
| 327 |
user_id = request.user_id
|
| 328 |
assistant_id = request.assistant_id
|
| 329 |
-
print_log("INFO",
|
| 330 |
-
logger.info(
|
| 331 |
user = get_user(user_id)
|
| 332 |
user.change_assistant(assistant_id)
|
| 333 |
logger.info(f"Assistant changed to {assistant_id}", extra={"user_id": user_id, "endpoint": "/change_assistant"})
|
|
@@ -359,7 +359,7 @@ def migrate_user(request: CreateUserItem, api_key: str = Security(get_api_key)):
|
|
| 359 |
def download_file_from_s3(filename, bucket):
|
| 360 |
user_id = filename.split('.')[0]
|
| 361 |
function_name = download_file_from_s3.__name__
|
| 362 |
-
logger.info(f"Downloading file {filename} from [
|
| 363 |
file_path = os.path.join('users', 'data', filename)
|
| 364 |
try:
|
| 365 |
if (AWS_ACCESS_KEY and AWS_SECRET_KEY):
|
|
@@ -368,8 +368,8 @@ def migrate_user(request: CreateUserItem, api_key: str = Security(get_api_key)):
|
|
| 368 |
session = boto3.session.Session()
|
| 369 |
s3_client = session.client('s3')
|
| 370 |
with open(file_path, 'wb') as f:
|
| 371 |
-
## Upload to
|
| 372 |
-
s3_client.download_fileobj(bucket, f"
|
| 373 |
logger.info(f"File {filename} downloaded successfully from S3", extra={'user_id': user_id, 'endpoint': function_name})
|
| 374 |
return True
|
| 375 |
except Exception as e:
|
|
@@ -435,7 +435,7 @@ def get_user_by_id(user_id: str, api_key: str = Security(get_api_key)):
|
|
| 435 |
user = get_user(user_id)
|
| 436 |
print_log("INFO", "Successfully retrieved user", extra={"user_id": user_id, "endpoint": "/get_user"})
|
| 437 |
logger.info("Successfully retrieved user", extra={"user_id": user_id, "endpoint": "/get_user"})
|
| 438 |
-
api_response = {"user": user.user_info, "user_messages": user.get_messages(
|
| 439 |
|
| 440 |
if user.goal:
|
| 441 |
api_response["goal"] = user.goal
|
|
@@ -664,7 +664,6 @@ def chat(request: ChatItem, api_key: str = Security(get_api_key)):
|
|
| 664 |
if recent_run:
|
| 665 |
user.cancel_run(recent_run)
|
| 666 |
response = user.send_message(user.get_recent_message())
|
| 667 |
-
|
| 668 |
finally:
|
| 669 |
print_log("INFO",f"Assistant: {response['content']}", extra={"user_id": request.user_id, "endpoint": "/chat"})
|
| 670 |
logger.info(f"Assistant: {response['content']}", extra={"user_id": request.user_id, "endpoint": "/chat"})
|
|
@@ -950,9 +949,6 @@ def add_session_completion_point_by_user(user_id: str, api_key: str = Security(g
|
|
| 950 |
user = get_user(user_id)
|
| 951 |
user.add_point_for_completing_session()
|
| 952 |
return {"response": "ok"}
|
| 953 |
-
|
| 954 |
-
|
| 955 |
-
|
| 956 |
except Exception as e:
|
| 957 |
print_log("ERROR",f"Error: {str(e)}", extra={"user_id": user_id, "endpoint": "/add_session_completion_point"}, exc_info=True)
|
| 958 |
logger.error(f"Error: {str(e)}", extra={"user_id": user_id, "endpoint": "/add_session_completion_point"}, exc_info=True)
|
|
|
|
| 8 |
import logging
|
| 9 |
import json
|
| 10 |
import regex as re
|
| 11 |
+
from datetime import datetime, timezone
|
| 12 |
from app.user import User
|
| 13 |
from typing import List, Optional, Callable
|
| 14 |
from openai import OpenAI
|
|
|
|
| 254 |
user_id: str
|
| 255 |
message: str
|
| 256 |
|
| 257 |
+
class AssistantItem(BaseModel):
|
| 258 |
user_id: str
|
| 259 |
assistant_id: str
|
| 260 |
|
|
|
|
| 270 |
status: str = "error"
|
| 271 |
code: int
|
| 272 |
message: str
|
| 273 |
+
timestamp: datetime = datetime.now(timezone.utc)
|
| 274 |
|
| 275 |
class BookingItem(BaseModel):
|
| 276 |
booking_id: str
|
|
|
|
| 323 |
|
| 324 |
# endpoint to change user assistant using user.change_to_latest_assistant()
|
| 325 |
@app.post("/change_assistant")
|
| 326 |
+
def change_assistant(request: AssistantItem, api_key: str = Security(get_api_key)):
|
| 327 |
user_id = request.user_id
|
| 328 |
assistant_id = request.assistant_id
|
| 329 |
+
print_log("INFO", "Changing assistant", extra={"user_id": user_id, "endpoint": "/change_assistant"})
|
| 330 |
+
logger.info("Changing assistant", extra={"user_id": user_id, "endpoint": "/change_assistant"})
|
| 331 |
user = get_user(user_id)
|
| 332 |
user.change_assistant(assistant_id)
|
| 333 |
logger.info(f"Assistant changed to {assistant_id}", extra={"user_id": user_id, "endpoint": "/change_assistant"})
|
|
|
|
| 359 |
def download_file_from_s3(filename, bucket):
|
| 360 |
user_id = filename.split('.')[0]
|
| 361 |
function_name = download_file_from_s3.__name__
|
| 362 |
+
logger.info(f"Downloading file {filename} from [staging] S3 bucket {bucket}", extra={'user_id': user_id, 'endpoint': function_name})
|
| 363 |
file_path = os.path.join('users', 'data', filename)
|
| 364 |
try:
|
| 365 |
if (AWS_ACCESS_KEY and AWS_SECRET_KEY):
|
|
|
|
| 368 |
session = boto3.session.Session()
|
| 369 |
s3_client = session.client('s3')
|
| 370 |
with open(file_path, 'wb') as f:
|
| 371 |
+
## Upload to Staging Folder
|
| 372 |
+
s3_client.download_fileobj(bucket, f"staging/users/{filename}", f)
|
| 373 |
logger.info(f"File {filename} downloaded successfully from S3", extra={'user_id': user_id, 'endpoint': function_name})
|
| 374 |
return True
|
| 375 |
except Exception as e:
|
|
|
|
| 435 |
user = get_user(user_id)
|
| 436 |
print_log("INFO", "Successfully retrieved user", extra={"user_id": user_id, "endpoint": "/get_user"})
|
| 437 |
logger.info("Successfully retrieved user", extra={"user_id": user_id, "endpoint": "/get_user"})
|
| 438 |
+
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}
|
| 439 |
|
| 440 |
if user.goal:
|
| 441 |
api_response["goal"] = user.goal
|
|
|
|
| 664 |
if recent_run:
|
| 665 |
user.cancel_run(recent_run)
|
| 666 |
response = user.send_message(user.get_recent_message())
|
|
|
|
| 667 |
finally:
|
| 668 |
print_log("INFO",f"Assistant: {response['content']}", extra={"user_id": request.user_id, "endpoint": "/chat"})
|
| 669 |
logger.info(f"Assistant: {response['content']}", extra={"user_id": request.user_id, "endpoint": "/chat"})
|
|
|
|
| 949 |
user = get_user(user_id)
|
| 950 |
user.add_point_for_completing_session()
|
| 951 |
return {"response": "ok"}
|
|
|
|
|
|
|
|
|
|
| 952 |
except Exception as e:
|
| 953 |
print_log("ERROR",f"Error: {str(e)}", extra={"user_id": user_id, "endpoint": "/add_session_completion_point"}, exc_info=True)
|
| 954 |
logger.error(f"Error: {str(e)}", extra={"user_id": user_id, "endpoint": "/add_session_completion_point"}, exc_info=True)
|
app/user.py
CHANGED
|
@@ -2,7 +2,7 @@ import json
|
|
| 2 |
import io
|
| 3 |
import os
|
| 4 |
import pandas as pd
|
| 5 |
-
from datetime import datetime
|
| 6 |
import json
|
| 7 |
from app.assistants import Assistant
|
| 8 |
import glob
|
|
@@ -43,7 +43,7 @@ class Index(BaseModel):
|
|
| 43 |
logger = logging.getLogger(__name__)
|
| 44 |
|
| 45 |
def get_current_datetime():
|
| 46 |
-
return datetime.now()
|
| 47 |
|
| 48 |
class ConversationManager:
|
| 49 |
def __init__(self, client, user, asst_id, intro_done=False):
|
|
@@ -52,7 +52,7 @@ class ConversationManager:
|
|
| 52 |
self.assistants = {'general': Assistant('asst_vnucWWELJlCWadfAARwyKkCW', self), 'intro': Assistant('asst_baczEK65KKvPWIUONSzdYH8j', self)}
|
| 53 |
|
| 54 |
self.client = client
|
| 55 |
-
self.state = {'date': pd.Timestamp.now().strftime("%d-%m-%Y %a %H:%M:%S")}
|
| 56 |
|
| 57 |
self.current_thread = self.create_thread()
|
| 58 |
self.daily_thread = None
|
|
@@ -206,6 +206,10 @@ class ConversationManager:
|
|
| 206 |
|
| 207 |
temp_thread = self.client.beta.threads.create(messages=messages)
|
| 208 |
logger.info(f"Created Temp Thread: {temp_thread}", extra={"user_id": self.user.user_id, "endpoint": "send_hidden_message"})
|
|
|
|
|
|
|
|
|
|
|
|
|
| 209 |
|
| 210 |
self.add_message_to_thread(temp_thread.id, "user", text)
|
| 211 |
|
|
@@ -217,10 +221,6 @@ class ConversationManager:
|
|
| 217 |
self.client.beta.threads.delete(temp_thread.id)
|
| 218 |
logger.info(f"Deleted Temp Thread: {temp_thread}", extra={"user_id": self.user.user_id, "endpoint": "send_hidden_message"})
|
| 219 |
|
| 220 |
-
if add_to_main:
|
| 221 |
-
logger.info(f"Adding message to main thread: {text}", extra={"user_id": self.user.user_id, "endpoint": "send_hidden_message"})
|
| 222 |
-
self.add_message_to_thread(self.current_thread.id, "assistant", text)
|
| 223 |
-
|
| 224 |
return response
|
| 225 |
|
| 226 |
def delete_hidden_messages(self, old_thread=None):
|
|
@@ -417,12 +417,69 @@ class User:
|
|
| 417 |
self.user_interaction_guidelines = self.generate_user_interaction_guidelines(user_info, client)
|
| 418 |
self.conversations = ConversationManager(client, self, asst_id)
|
| 419 |
|
| 420 |
-
def add_recent_wins(self, wins):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 421 |
if len(self.recent_wins)<5:
|
| 422 |
-
self.recent_wins.insert(0,
|
| 423 |
else:
|
| 424 |
self.recent_wins.pop()
|
| 425 |
-
self.recent_wins.insert(0,
|
| 426 |
|
| 427 |
def add_life_score_point(self, variable, points_added, notes):
|
| 428 |
if variable == 'Personal Growth':
|
|
@@ -461,13 +518,13 @@ class User:
|
|
| 461 |
current_goal = self.get_current_goal(full=True)
|
| 462 |
if current_goal:
|
| 463 |
current_goal.status = "COMPLETED"
|
| 464 |
-
current_goal.updated_at = pd.Timestamp.now().strftime("%d-%m-%Y %a %H:%M:%S")
|
| 465 |
return current_goal.content
|
| 466 |
|
| 467 |
for g in self.goal:
|
| 468 |
if g.content == goal:
|
| 469 |
g.status = status
|
| 470 |
-
g.updated_at = pd.Timestamp.now().strftime("%d-%m-%Y %a %H:%M:%S")
|
| 471 |
if content:
|
| 472 |
g.content = content
|
| 473 |
return True
|
|
@@ -479,22 +536,22 @@ class User:
|
|
| 479 |
if completed:
|
| 480 |
self.update_goal(current_goal, "COMPLETED")
|
| 481 |
self.add_life_score_point(variable = goal_area, points_added = 30, notes = "Completing a Goal")
|
| 482 |
-
self.add_recent_wins(wins = "You have completed your goal!")
|
| 483 |
|
| 484 |
if current_goal is None:
|
| 485 |
-
new_goal = UserDataItem(role="assistant", content=goal, area=goal_area, user_id=self.user_id, status="ONGOING", created_at=pd.Timestamp.now().strftime("%d-%m-%Y %a %H:%M:%S"), updated_at=pd.Timestamp.now().strftime("%d-%m-%Y %a %H:%M:%S"))
|
| 486 |
self.goal.append(new_goal)
|
| 487 |
self.add_life_score_point(variable = goal_area, points_added = 10, notes = "Setting a Goal")
|
| 488 |
-
self.add_recent_wins(wins = "You have set
|
| 489 |
else:
|
| 490 |
if add:
|
| 491 |
if current_goal:
|
| 492 |
# update current_goal status to "IDLE"
|
| 493 |
self.update_goal(current_goal, "IDLE")
|
| 494 |
-
new_goal = UserDataItem(role="assistant", content=goal, area=goal_area, user_id=self.user_id, status="ONGOING", created_at=pd.Timestamp.now().strftime("%d-%m-%Y %a %H:%M:%S"), updated_at=pd.Timestamp.now().strftime("%d-%m-%Y %a %H:%M:%S"))
|
| 495 |
self.goal.append(new_goal)
|
| 496 |
self.add_life_score_point(variable = goal_area, points_added = 10, notes = "Setting a Goal")
|
| 497 |
-
self.add_recent_wins(wins = "You have set a new goal!")
|
| 498 |
else:
|
| 499 |
self.update_goal(current_goal, "ONGOING", content=goal)
|
| 500 |
|
|
@@ -502,7 +559,7 @@ class User:
|
|
| 502 |
for ma in self.recommended_micro_actions:
|
| 503 |
if ma.content == micro_action:
|
| 504 |
ma.status = status
|
| 505 |
-
ma.updated_at = pd.Timestamp.now().strftime("%d-%m-%Y %a %H:%M:%S")
|
| 506 |
return True
|
| 507 |
return False
|
| 508 |
|
|
@@ -527,6 +584,7 @@ class User:
|
|
| 527 |
self.reminders = None
|
| 528 |
self.recent_wins = []
|
| 529 |
|
|
|
|
| 530 |
def generate_user_interaction_guidelines(self, user_info, client):
|
| 531 |
logger.info(f"Generating user interaction guidelines for user: {self.user_id}", extra={"user_id": self.user_id, "endpoint": "generate_user_interaction_guidelines"})
|
| 532 |
# prompt = f"A 'profile' is a document containing rich insights on users for the purpose of \
|
|
@@ -661,6 +719,28 @@ class User:
|
|
| 661 |
return index
|
| 662 |
|
| 663 |
def set_reminder(self, reminder):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 664 |
# generate uuid for this reminder
|
| 665 |
reminder['id'] = generate_uuid()
|
| 666 |
action = reminder['action']
|
|
@@ -684,6 +764,7 @@ class User:
|
|
| 684 |
if index == -1:
|
| 685 |
logger.info(f"Could not find a mathcing reminder to delete: {reminder}", extra={"user_id": self.user_id, "endpoint": "set_reminder"})
|
| 686 |
else:
|
|
|
|
| 687 |
self.reminders[index]['action'] = 'delete'
|
| 688 |
logger.info(f"Reminder {old_reminder} has been marked for deletion", extra={"user_id": self.user_id, "endpoint": "set_reminder"})
|
| 689 |
else:
|
|
@@ -705,107 +786,6 @@ class User:
|
|
| 705 |
self.conversations.intro_done = True
|
| 706 |
|
| 707 |
def do_theme(self, theme, date, day):
|
| 708 |
-
# Fetching legendary persona info
|
| 709 |
-
db_params = {
|
| 710 |
-
'dbname': 'ourcoach',
|
| 711 |
-
'user': 'ourcoach',
|
| 712 |
-
'password': 'hvcTL3kN3pOG5KteT17T',
|
| 713 |
-
'host': 'staging-ourcoach.cx8se8o0iaiy.ap-southeast-1.rds.amazonaws.com',
|
| 714 |
-
'port': '5432'
|
| 715 |
-
}
|
| 716 |
-
with psycopg2.connect(**db_params) as conn:
|
| 717 |
-
with conn.cursor() as cursor:
|
| 718 |
-
query = sql.SQL("SELECT * FROM {table} WHERE id = %s").format(table=sql.Identifier('public', 'users'))
|
| 719 |
-
cursor.execute(query, (self.user_id,))
|
| 720 |
-
row = cursor.fetchone()
|
| 721 |
-
if (row):
|
| 722 |
-
colnames = [desc[0] for desc in cursor.description]
|
| 723 |
-
user_data = dict(zip(colnames, row))
|
| 724 |
-
user_data_clean = json.loads(user_data['onboarding'])
|
| 725 |
-
user_legendary_persona = user_data_clean.get('legendPersona', '')
|
| 726 |
-
|
| 727 |
-
if "Coach Steve" in user_legendary_persona:
|
| 728 |
-
persona_name = 'Steve Jobs'
|
| 729 |
-
elif "Coach Aris" in user_legendary_persona:
|
| 730 |
-
persona_name = 'Aristotle'
|
| 731 |
-
elif "Coach Teresa" in user_legendary_persona:
|
| 732 |
-
persona_name = 'Mother Teresa'
|
| 733 |
-
else:
|
| 734 |
-
persona_name = user_legendary_persona
|
| 735 |
-
|
| 736 |
-
if "Coach Steve" in user_legendary_persona or "Steve Jobs" in user_legendary_persona:
|
| 737 |
-
knowledge = """
|
| 738 |
-
1. Vision and Creativity: Encouraging students to think big and innovate.
|
| 739 |
-
2. Simplicity: Teaching the power of focus and clarity in life and work.
|
| 740 |
-
3. Perfectionism: Instilling attention to detail and striving for excellence.
|
| 741 |
-
4. Passion-Driven Work: Encouraging students to follow what truly inspires them.
|
| 742 |
-
5. Resilience: Emphasizing persistence in the face of failure and rejection.
|
| 743 |
-
6. Integration of Art and Science: Inspiring holistic thinking by combining creativity with logic.
|
| 744 |
-
7. Unique Value: Teaching students to focus on what makes them stand out.
|
| 745 |
-
8. Relentless focus on perfection and quality.
|
| 746 |
-
"""
|
| 747 |
-
elif "Eleanor Roosevelt" in user_legendary_persona:
|
| 748 |
-
knowledge = """
|
| 749 |
-
1. Empowerment: Helping students find their voice and advocate for themselves.
|
| 750 |
-
2. Courage: Encouraging students to face fears and take bold action.
|
| 751 |
-
3. Human Rights and Inclusion: Teaching the value of respect and equality for all.
|
| 752 |
-
4. Service Leadership: Inspiring students to lead through compassion and empathy.
|
| 753 |
-
5. Resilience: Helping students overcome adversity with grace and strength.
|
| 754 |
-
6. Continuous Growth: Encouraging self-improvement and lifelong learning.
|
| 755 |
-
7. Global Perspective: Instilling the importance of collaboration and understanding across cultures.
|
| 756 |
-
"""
|
| 757 |
-
elif "Coach Aris" in user_legendary_persona or "Aristotle" in user_legendary_persona:
|
| 758 |
-
knowledge = """
|
| 759 |
-
1. The concept of eudaimonia (flourishing).
|
| 760 |
-
2. Virtue ethics as a framework for moral living.
|
| 761 |
-
3. Rational thinking as the path to the good life.
|
| 762 |
-
4. The “Golden Mean” – balance as a virtue.
|
| 763 |
-
5. Foundational ideas in logic, metaphysics, and natural sciences.
|
| 764 |
-
"""
|
| 765 |
-
elif "Coach Teresa" in user_legendary_persona or "Mother Teresa" in user_legendary_persona:
|
| 766 |
-
knowledge = """
|
| 767 |
-
1. Radical compassion for the poorest of the poor.
|
| 768 |
-
2. Dedication to selfless service and humility.
|
| 769 |
-
3. Advocating love as the universal language.
|
| 770 |
-
4. Living out faith through action.
|
| 771 |
-
5.Inspiring others to help without expectation of reward.
|
| 772 |
-
"""
|
| 773 |
-
elif "Viktor Frankl" in user_legendary_persona:
|
| 774 |
-
knowledge = """
|
| 775 |
-
1. Logotherapy: finding meaning as the essence of life.
|
| 776 |
-
2. Turning suffering into a source of purpose.
|
| 777 |
-
3. Emphasizing freedom in how we respond to life’s challenges.
|
| 778 |
-
4. Hope and resilience through existential crises.
|
| 779 |
-
5. Advocating for a life guided by values and responsibility.
|
| 780 |
-
"""
|
| 781 |
-
elif "Marcus Aurelius" in user_legendary_persona:
|
| 782 |
-
knowledge = """
|
| 783 |
-
1. Stoicism: emphasizing self-discipline, resilience, and rationality.
|
| 784 |
-
2. Meditations: reflections on inner peace and leadership.
|
| 785 |
-
3. Acceptance of life’s impermanence and hardships.
|
| 786 |
-
4. Living in harmony with nature and reason.
|
| 787 |
-
5. Leading with humility and service as emperor.
|
| 788 |
-
"""
|
| 789 |
-
elif "Maya Angelou" in user_legendary_persona:
|
| 790 |
-
knowledge = """
|
| 791 |
-
1. Self-Worth: Teaching the importance of self-love and embracing one's unique identity.
|
| 792 |
-
2. Resilience: Inspiring students to rise above hardships and turn pain into strength.
|
| 793 |
-
3. The Power of Words: Encouraging self-expression and the impact of storytelling.
|
| 794 |
-
4. Empathy and Compassion: Teaching kindness and understanding in relationships and community.
|
| 795 |
-
5. Courage: Inspiring boldness to live authentically and fearlessly.
|
| 796 |
-
6. Advocacy for Justice: Guiding students to stand up for what’s right and fight for equality.
|
| 797 |
-
7. Gratitude and Joy: Emphasizing the value of appreciating life's beauty, even in struggle.
|
| 798 |
-
8. Living with Purpose: Encouraging a life filled with intention, meaning, and contribution.
|
| 799 |
-
"""
|
| 800 |
-
elif "Mahatma Gandhi" in user_legendary_persona:
|
| 801 |
-
knowledge = """
|
| 802 |
-
1. Nonviolence (Ahimsa) as a philosophy and practice.
|
| 803 |
-
2. Civil disobedience as a method for societal change.
|
| 804 |
-
3. Advocacy for self-reliance (Swaraj) and simplicity in life.
|
| 805 |
-
4. Bridging spirituality and activism.
|
| 806 |
-
5. Emphasis on truth (Satya) as a guiding principle.
|
| 807 |
-
"""
|
| 808 |
-
|
| 809 |
logger.info(f"Doing theme: {theme}", extra={"user_id": self.user_id, "endpoint": "do_theme"})
|
| 810 |
|
| 811 |
if self.reminders is not None and len(self.reminders):
|
|
@@ -820,45 +800,45 @@ class User:
|
|
| 820 |
for reminder in reminders:
|
| 821 |
if reminder['timestamp'].date() == pd.to_datetime(date).date():
|
| 822 |
logger.info(f"Reminder found for today ({pd.to_datetime(date).date()}): {reminder}", extra={"user_id": self.user_id, "endpoint": "do_theme"})
|
| 823 |
-
if
|
| 824 |
theme = "MICRO_ACTION_STATE"
|
| 825 |
break
|
| 826 |
else:
|
| 827 |
logger.info(f"No reminders found for today ({pd.to_datetime(date).date()})", extra={"user_id": self.user_id, "endpoint": "do_theme"})
|
| 828 |
|
| 829 |
if theme == "MOTIVATION_INSPIRATION_STATE":
|
| 830 |
-
formatted_message = MOTIVATION_INSPIRATION_STATE.format(self.get_current_goal(), day, len(self.growth_plan.array)
|
| 831 |
elif theme == "PROGRESS_REFLECTION_STATE":
|
| 832 |
-
formatted_message = PROGRESS_REFLECTION_STATE.format(self.get_current_goal(), day, len(self.growth_plan.array)
|
| 833 |
if len(self.challenges):
|
| 834 |
challenge = self.challenges.pop(0)
|
| 835 |
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) **"
|
| 836 |
elif theme == "MICRO_ACTION_STATE":
|
| 837 |
reminder_message = "\n".join([f"{i+1}. {reminder}" for i, reminder in enumerate(reminders)]) if reminders else "User has no postponed micro-actions"
|
| 838 |
|
| 839 |
-
formatted_message = MICRO_ACTION_STATE.format(self.get_current_goal(), day, len(self.growth_plan.array),
|
| 840 |
if len(self.recommended_micro_actions):
|
| 841 |
todays_micro_action = self.recommended_micro_actions.pop(0)
|
| 842 |
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) **"
|
| 843 |
elif theme == "OPEN_DISCUSSION_STATE":
|
| 844 |
-
formatted_message = OPEN_DISCUSSION_STATE.format(self.get_current_goal(), day, len(self.growth_plan.array)
|
| 845 |
if len(self.other_focusses):
|
| 846 |
focus = self.other_focusses.pop(0)
|
| 847 |
formatted_message += f"\n\n** IMPORTANT: Today, focus the discussion on: {focus.content}, which they discussed during their growth guide session (let the user know we are bringing it up because of this) **"
|
| 848 |
elif theme == "PROGRESS_SUMMARY_STATE":
|
| 849 |
-
formatted_message = PROGRESS_SUMMARY_STATE.format(self.get_current_goal(), day, len(self.growth_plan.array)
|
| 850 |
elif theme == "FINAL_SUMMARY_STATE":
|
| 851 |
-
formatted_message = FINAL_SUMMARY_STATE.format(self.get_current_goal(), day, len(self.growth_plan.array)
|
| 852 |
elif theme == "EDUCATION_STATE":
|
| 853 |
-
formatted_message = EDUCATION_STATE.format(self.get_current_goal(), day, len(self.growth_plan.array)
|
| 854 |
elif theme == "FOLLUP_ACTION_STATE":
|
| 855 |
reminder_message = "\n".join([f"{i+1}. {reminder}" for i, reminder in enumerate(reminders)]) if reminders else "User has no postponed micro-actions"
|
| 856 |
-
formatted_message = FOLLUP_ACTION_STATE.format(self.get_current_goal(), day, len(self.growth_plan.array),
|
| 857 |
elif theme == "FUNFACT_STATE":
|
| 858 |
topics = ["Fun Fact about the User's Goal", "How Personality Type is affecting/shaping their behaviour towards the goal", "How Love Language may impact and be relevant toward the goal"]
|
| 859 |
randomized_topic = random.choice(topics)
|
| 860 |
-
formatted_message = FUNFACT_STATE.format(self.get_current_goal(), day, len(self.growth_plan.array),
|
| 861 |
-
|
| 862 |
# prompt = f"""** It is a new day: {date} **
|
| 863 |
# Additional System Instruction:
|
| 864 |
# - Remember all of the user's personal information. Use this information to be as personalised as possible when conversing by including it in your responses where relevant.
|
|
@@ -872,11 +852,8 @@ class User:
|
|
| 872 |
# """
|
| 873 |
|
| 874 |
prompt = f"""** It is a new day: {date} ({day}) 10:00:00 **
|
| 875 |
-
|
| 876 |
-
*Send a message that suits the morning time*
|
| 877 |
-
|
| 878 |
Additional System Instruction:
|
| 879 |
-
|
| 880 |
1. Focus on giving more wisdom than questions:
|
| 881 |
- Provide assertive guidance, encouragement, validation, and different viewpoints.
|
| 882 |
- Be critical and challenge the user's arguments as needed.
|
|
@@ -897,9 +874,9 @@ class User:
|
|
| 897 |
- Enrich content with user information.
|
| 898 |
- Avoid being a "boring" coach with generic questions or advice.
|
| 899 |
|
| 900 |
-
6. Channel the energy, wisdom, and mindset of
|
| 901 |
-
- Reiterate
|
| 902 |
-
- Explain
|
| 903 |
|
| 904 |
7. You may greet the user by name on a new day, but no need to use their name in every message.
|
| 905 |
|
|
@@ -913,7 +890,7 @@ class User:
|
|
| 913 |
if theme == "MICRO_ACTION_STATE":
|
| 914 |
# check for any recommended microactions
|
| 915 |
logger.info(f"Checking for recommended micro actions", extra={"user_id": self.user_id, "endpoint": "do_theme"})
|
| 916 |
-
micro_action = UserDataItem(role="assistant", area=self.get_current_goal(full=True).area, content=response['content'], user_id=self.user_id, status="PENDING", created_at=pd.Timestamp.now().strftime("%d-%m-%Y %a %H:%M:%S"), updated_at=pd.Timestamp.now().strftime("%d-%m-%Y %a %H:%M:%S"))
|
| 917 |
logger.info(f"Recommended Micro Action: {micro_action}", extra={"user_id": self.user_id, "endpoint": "do_theme"})
|
| 918 |
self.micro_actions.append(micro_action)
|
| 919 |
|
|
@@ -933,16 +910,17 @@ class User:
|
|
| 933 |
if self.reminders is not None and len(self.reminders):
|
| 934 |
# remove all reminders which 'recurrence' is 'once' or 'action' is 'delete' or the date is < today
|
| 935 |
# this is to ensure that only reminders with recurrence and future reminder are kept
|
| 936 |
-
|
|
|
|
| 937 |
logger.info(f"Active Reminders: {self.reminders}", extra={"user_id": self.user_id, "endpoint": "user_change_date"})
|
| 938 |
|
| 939 |
## ADD POINT FOR CHANGE DATE
|
| 940 |
if self.growth_plan.current()['day'] == 7:
|
| 941 |
self.add_life_score_point(variable = self.get_current_goal(full=True).area, points_added = 5, notes = "Reaching Day 7")
|
| 942 |
-
self.add_recent_wins(wins = "You have reached Day 7 of your growth journey!")
|
| 943 |
elif self.growth_plan.current()['day'] == 14:
|
| 944 |
self.add_life_score_point(variable = self.get_current_goal(full=True).area, points_added = 10, notes = "Reaching Day 14")
|
| 945 |
-
self.add_recent_wins(wins = "You have finished your growth journey!")
|
| 946 |
|
| 947 |
logger.info(f"Today's action is {action}", extra={"user_id": self.user_id, "endpoint": "user_change_date"})
|
| 948 |
|
|
@@ -1053,7 +1031,7 @@ class User:
|
|
| 1053 |
)
|
| 1054 |
|
| 1055 |
try:
|
| 1056 |
-
current_time = datetime.now().strftime("%d-%m-%Y %a %H:%M:%S")
|
| 1057 |
|
| 1058 |
response = self.client.beta.chat.completions.parse(
|
| 1059 |
model="gpt-4o",
|
|
@@ -1093,10 +1071,12 @@ class User:
|
|
| 1093 |
The user has a current goal: {self.get_current_goal()}
|
| 1094 |
The user provided a new goal: {goal_text}
|
| 1095 |
|
| 1096 |
-
Determine if the new goal is the
|
| 1097 |
-
If it's the
|
| 1098 |
-
If it's
|
| 1099 |
-
|
|
|
|
|
|
|
| 1100 |
Your response will be the final goal. You will also need to determine the area of this
|
| 1101 |
final goal by choosing one of these areas that suits the final goal:
|
| 1102 |
"Personal Growth", "Career Growth", "Relationship", "Mental Well-Being", "Health and Wellness"
|
|
@@ -1107,6 +1087,40 @@ class User:
|
|
| 1107 |
goal: str (the final goal),
|
| 1108 |
area: str (the area of the goal)
|
| 1109 |
}}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1110 |
"""
|
| 1111 |
|
| 1112 |
response = self.client.chat.completions.create(
|
|
@@ -1168,27 +1182,27 @@ class User:
|
|
| 1168 |
def update_micro_action_status(self, completed_micro_action):
|
| 1169 |
if completed_micro_action:
|
| 1170 |
self.micro_actions[-1].status = "COMPLETE"
|
| 1171 |
-
self.micro_actions[-1].updated_at = pd.Timestamp.now().strftime("%d-%m-%Y %a %H:%M:%S")
|
| 1172 |
|
| 1173 |
num_of_micro_actions_completed = sum(1 for item in self.micro_actions if item.status == 'COMPLETE')
|
| 1174 |
|
| 1175 |
if (num_of_micro_actions_completed in (1,3,5)) or (num_of_micro_actions_completed % 10 == 0 and num_of_micro_actions_completed != 0):
|
| 1176 |
self.add_life_score_point(variable = self.get_current_goal(full=True).area, points_added = 10, notes = f"Completing the {num_of_micro_actions_completed}-th micro-action")
|
| 1177 |
-
self.add_recent_wins(wins = "You have completed a micro action!")
|
| 1178 |
|
| 1179 |
def trigger_deep_reflection_point(self, area_of_deep_reflection):
|
| 1180 |
if len(area_of_deep_reflection)>0:
|
| 1181 |
for area in area_of_deep_reflection:
|
| 1182 |
self.add_life_score_point(variable = area, points_added = 5, notes = f"Doing a deep reflection about {area}")
|
| 1183 |
-
self.add_recent_wins(wins = f"You have done a deep reflection about your {area}!")
|
| 1184 |
|
| 1185 |
def add_point_for_booking(self):
|
| 1186 |
self.add_life_score_point(variable = self.get_current_goal(full=True).area, points_added = 5, notes = "Booking a GG session")
|
| 1187 |
-
self.add_recent_wins(wins = "You have booked a Growth Guide session!")
|
| 1188 |
|
| 1189 |
def add_point_for_completing_session(self):
|
| 1190 |
self.add_life_score_point(variable = self.get_current_goal(full=True).area, points_added = 20, notes = "Completing a GG session")
|
| 1191 |
-
self.add_recent_wins(wins = "You have completed a Growth Guide session!")
|
| 1192 |
|
| 1193 |
def build_ourcoach_report(self, overview, action_plan, gg_session_notes):
|
| 1194 |
logger.info(f"Building ourcoach report", extra={"user_id": self.user_id, "endpoint": "build_ourcoach_report"})
|
|
|
|
| 2 |
import io
|
| 3 |
import os
|
| 4 |
import pandas as pd
|
| 5 |
+
from datetime import datetime, timezone
|
| 6 |
import json
|
| 7 |
from app.assistants import Assistant
|
| 8 |
import glob
|
|
|
|
| 43 |
logger = logging.getLogger(__name__)
|
| 44 |
|
| 45 |
def get_current_datetime():
|
| 46 |
+
return datetime.now(timezone.utc)
|
| 47 |
|
| 48 |
class ConversationManager:
|
| 49 |
def __init__(self, client, user, asst_id, intro_done=False):
|
|
|
|
| 52 |
self.assistants = {'general': Assistant('asst_vnucWWELJlCWadfAARwyKkCW', self), 'intro': Assistant('asst_baczEK65KKvPWIUONSzdYH8j', self)}
|
| 53 |
|
| 54 |
self.client = client
|
| 55 |
+
self.state = {'date': pd.Timestamp.now(tz='UTC').strftime("%d-%m-%Y %a %H:%M:%S")}
|
| 56 |
|
| 57 |
self.current_thread = self.create_thread()
|
| 58 |
self.daily_thread = None
|
|
|
|
| 206 |
|
| 207 |
temp_thread = self.client.beta.threads.create(messages=messages)
|
| 208 |
logger.info(f"Created Temp Thread: {temp_thread}", extra={"user_id": self.user.user_id, "endpoint": "send_hidden_message"})
|
| 209 |
+
|
| 210 |
+
if add_to_main:
|
| 211 |
+
logger.info(f"Adding message to main thread: {text}", extra={"user_id": self.user.user_id, "endpoint": "send_hidden_message"})
|
| 212 |
+
self.add_message_to_thread(self.current_thread.id, "assistant", text)
|
| 213 |
|
| 214 |
self.add_message_to_thread(temp_thread.id, "user", text)
|
| 215 |
|
|
|
|
| 221 |
self.client.beta.threads.delete(temp_thread.id)
|
| 222 |
logger.info(f"Deleted Temp Thread: {temp_thread}", extra={"user_id": self.user.user_id, "endpoint": "send_hidden_message"})
|
| 223 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 224 |
return response
|
| 225 |
|
| 226 |
def delete_hidden_messages(self, old_thread=None):
|
|
|
|
| 417 |
self.user_interaction_guidelines = self.generate_user_interaction_guidelines(user_info, client)
|
| 418 |
self.conversations = ConversationManager(client, self, asst_id)
|
| 419 |
|
| 420 |
+
def add_recent_wins(self, wins, context = None):
|
| 421 |
+
prompt = f"""
|
| 422 |
+
## Role
|
| 423 |
+
You are an expert in writing achievement message and progress notification. Your task is to use the user's achievement and context to formulate a short and creative achievement message/progress notification. The output must be a one sentence short message (less than 15 words) in this JSON output schema:
|
| 424 |
+
|
| 425 |
+
```json
|
| 426 |
+
{{
|
| 427 |
+
achievement_message: str
|
| 428 |
+
}}
|
| 429 |
+
```
|
| 430 |
+
|
| 431 |
+
Note: No need to mention the user's name. Make it concise (less than 15 words)
|
| 432 |
+
|
| 433 |
+
## Example
|
| 434 |
+
User's achievement: Completing a Task
|
| 435 |
+
Achievement context: The user has completed a 10k run
|
| 436 |
+
|
| 437 |
+
Output:
|
| 438 |
+
```
|
| 439 |
+
{{
|
| 440 |
+
achievement_message: You crushed it! Completing that 10k run is a huge milestone—way to go!
|
| 441 |
+
}}
|
| 442 |
+
```
|
| 443 |
+
|
| 444 |
+
## User Input
|
| 445 |
+
|
| 446 |
+
User's achievement: {wins}
|
| 447 |
+
Achievement context: {context}
|
| 448 |
+
"""
|
| 449 |
+
|
| 450 |
+
response = self.client.chat.completions.create(
|
| 451 |
+
model="gpt-4o",
|
| 452 |
+
messages=[{"role": "user", "content": prompt}],
|
| 453 |
+
response_format = {
|
| 454 |
+
"type": "json_schema",
|
| 455 |
+
"json_schema": {
|
| 456 |
+
"name": "achievement_message_schema",
|
| 457 |
+
"strict": True,
|
| 458 |
+
"schema": {
|
| 459 |
+
"type": "object",
|
| 460 |
+
"properties": {
|
| 461 |
+
"achievement_message": {
|
| 462 |
+
"type": "string",
|
| 463 |
+
"description": "A message indicating an achievement."
|
| 464 |
+
}
|
| 465 |
+
},
|
| 466 |
+
"required": [
|
| 467 |
+
"achievement_message"
|
| 468 |
+
],
|
| 469 |
+
"additionalProperties": False
|
| 470 |
+
}
|
| 471 |
+
}
|
| 472 |
+
},
|
| 473 |
+
temperature=1
|
| 474 |
+
)
|
| 475 |
+
|
| 476 |
+
achievement_message = json.loads(response.choices[0].message.content)['achievement_message']
|
| 477 |
+
|
| 478 |
if len(self.recent_wins)<5:
|
| 479 |
+
self.recent_wins.insert(0,achievement_message)
|
| 480 |
else:
|
| 481 |
self.recent_wins.pop()
|
| 482 |
+
self.recent_wins.insert(0,achievement_message)
|
| 483 |
|
| 484 |
def add_life_score_point(self, variable, points_added, notes):
|
| 485 |
if variable == 'Personal Growth':
|
|
|
|
| 518 |
current_goal = self.get_current_goal(full=True)
|
| 519 |
if current_goal:
|
| 520 |
current_goal.status = "COMPLETED"
|
| 521 |
+
current_goal.updated_at = pd.Timestamp.now(tz='UTC').strftime("%d-%m-%Y %a %H:%M:%S")
|
| 522 |
return current_goal.content
|
| 523 |
|
| 524 |
for g in self.goal:
|
| 525 |
if g.content == goal:
|
| 526 |
g.status = status
|
| 527 |
+
g.updated_at = pd.Timestamp.now(tz='UTC').strftime("%d-%m-%Y %a %H:%M:%S")
|
| 528 |
if content:
|
| 529 |
g.content = content
|
| 530 |
return True
|
|
|
|
| 536 |
if completed:
|
| 537 |
self.update_goal(current_goal, "COMPLETED")
|
| 538 |
self.add_life_score_point(variable = goal_area, points_added = 30, notes = "Completing a Goal")
|
| 539 |
+
self.add_recent_wins(wins = "You have completed your goal!", context = current_goal)
|
| 540 |
|
| 541 |
if current_goal is None:
|
| 542 |
+
new_goal = UserDataItem(role="assistant", content=goal, area=goal_area, user_id=self.user_id, status="ONGOING", created_at=pd.Timestamp.now(tz='UTC').strftime("%d-%m-%Y %a %H:%M:%S"), updated_at=pd.Timestamp.now(tz='UTC').strftime("%d-%m-%Y %a %H:%M:%S"))
|
| 543 |
self.goal.append(new_goal)
|
| 544 |
self.add_life_score_point(variable = goal_area, points_added = 10, notes = "Setting a Goal")
|
| 545 |
+
self.add_recent_wins(wins = "You have set your first goal!", context = new_goal.content)
|
| 546 |
else:
|
| 547 |
if add:
|
| 548 |
if current_goal:
|
| 549 |
# update current_goal status to "IDLE"
|
| 550 |
self.update_goal(current_goal, "IDLE")
|
| 551 |
+
new_goal = UserDataItem(role="assistant", content=goal, area=goal_area, user_id=self.user_id, status="ONGOING", created_at=pd.Timestamp.now(tz='UTC').strftime("%d-%m-%Y %a %H:%M:%S"), updated_at=pd.Timestamp.now(tz='UTC').strftime("%d-%m-%Y %a %H:%M:%S"))
|
| 552 |
self.goal.append(new_goal)
|
| 553 |
self.add_life_score_point(variable = goal_area, points_added = 10, notes = "Setting a Goal")
|
| 554 |
+
self.add_recent_wins(wins = "You have set a new goal!", context = new_goal.content)
|
| 555 |
else:
|
| 556 |
self.update_goal(current_goal, "ONGOING", content=goal)
|
| 557 |
|
|
|
|
| 559 |
for ma in self.recommended_micro_actions:
|
| 560 |
if ma.content == micro_action:
|
| 561 |
ma.status = status
|
| 562 |
+
ma.updated_at = pd.Timestamp.now(tz='UTC').strftime("%d-%m-%Y %a %H:%M:%S")
|
| 563 |
return True
|
| 564 |
return False
|
| 565 |
|
|
|
|
| 584 |
self.reminders = None
|
| 585 |
self.recent_wins = []
|
| 586 |
|
| 587 |
+
|
| 588 |
def generate_user_interaction_guidelines(self, user_info, client):
|
| 589 |
logger.info(f"Generating user interaction guidelines for user: {self.user_id}", extra={"user_id": self.user_id, "endpoint": "generate_user_interaction_guidelines"})
|
| 590 |
# prompt = f"A 'profile' is a document containing rich insights on users for the purpose of \
|
|
|
|
| 719 |
return index
|
| 720 |
|
| 721 |
def set_reminder(self, reminder):
|
| 722 |
+
db_params = {
|
| 723 |
+
'dbname': 'ourcoach',
|
| 724 |
+
'user': 'ourcoach',
|
| 725 |
+
'password': 'hvcTL3kN3pOG5KteT17T',
|
| 726 |
+
'host': 'staging-ourcoach.cx8se8o0iaiy.ap-southeast-1.rds.amazonaws.com',
|
| 727 |
+
'port': '5432'
|
| 728 |
+
}
|
| 729 |
+
with psycopg2.connect(**db_params) as conn:
|
| 730 |
+
with conn.cursor() as cursor:
|
| 731 |
+
query = sql.SQL("SELECT * FROM {table} WHERE id = %s").format(table=sql.Identifier('public', 'users'))
|
| 732 |
+
cursor.execute(query, (self.user_id,))
|
| 733 |
+
row = cursor.fetchone()
|
| 734 |
+
if (row):
|
| 735 |
+
colnames = [desc[0] for desc in cursor.description]
|
| 736 |
+
user_data = dict(zip(colnames, row))
|
| 737 |
+
user_timezone = user_data['timezone']
|
| 738 |
+
|
| 739 |
+
# Convert to UTC
|
| 740 |
+
reminder['timestamp_local'] = reminder['timestamp']
|
| 741 |
+
reminder['local_timezone'] = user_timezone
|
| 742 |
+
reminder['timestamp'] = reminder['timestamp'].tz_localize(user_timezone).tz_convert("UTC")
|
| 743 |
+
|
| 744 |
# generate uuid for this reminder
|
| 745 |
reminder['id'] = generate_uuid()
|
| 746 |
action = reminder['action']
|
|
|
|
| 764 |
if index == -1:
|
| 765 |
logger.info(f"Could not find a mathcing reminder to delete: {reminder}", extra={"user_id": self.user_id, "endpoint": "set_reminder"})
|
| 766 |
else:
|
| 767 |
+
old_reminder = self.reminders[index]
|
| 768 |
self.reminders[index]['action'] = 'delete'
|
| 769 |
logger.info(f"Reminder {old_reminder} has been marked for deletion", extra={"user_id": self.user_id, "endpoint": "set_reminder"})
|
| 770 |
else:
|
|
|
|
| 786 |
self.conversations.intro_done = True
|
| 787 |
|
| 788 |
def do_theme(self, theme, date, day):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 789 |
logger.info(f"Doing theme: {theme}", extra={"user_id": self.user_id, "endpoint": "do_theme"})
|
| 790 |
|
| 791 |
if self.reminders is not None and len(self.reminders):
|
|
|
|
| 800 |
for reminder in reminders:
|
| 801 |
if reminder['timestamp'].date() == pd.to_datetime(date).date():
|
| 802 |
logger.info(f"Reminder found for today ({pd.to_datetime(date).date()}): {reminder}", extra={"user_id": self.user_id, "endpoint": "do_theme"})
|
| 803 |
+
if theme != "FINAL_SUMMARY_STATE":
|
| 804 |
theme = "MICRO_ACTION_STATE"
|
| 805 |
break
|
| 806 |
else:
|
| 807 |
logger.info(f"No reminders found for today ({pd.to_datetime(date).date()})", extra={"user_id": self.user_id, "endpoint": "do_theme"})
|
| 808 |
|
| 809 |
if theme == "MOTIVATION_INSPIRATION_STATE":
|
| 810 |
+
formatted_message = MOTIVATION_INSPIRATION_STATE.format(self.get_current_goal(), day, len(self.growth_plan.array))
|
| 811 |
elif theme == "PROGRESS_REFLECTION_STATE":
|
| 812 |
+
formatted_message = PROGRESS_REFLECTION_STATE.format(self.get_current_goal(), day, len(self.growth_plan.array))
|
| 813 |
if len(self.challenges):
|
| 814 |
challenge = self.challenges.pop(0)
|
| 815 |
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) **"
|
| 816 |
elif theme == "MICRO_ACTION_STATE":
|
| 817 |
reminder_message = "\n".join([f"{i+1}. {reminder}" for i, reminder in enumerate(reminders)]) if reminders else "User has no postponed micro-actions"
|
| 818 |
|
| 819 |
+
formatted_message = MICRO_ACTION_STATE.format(self.get_current_goal(), day, len(self.growth_plan.array), reminder_message)
|
| 820 |
if len(self.recommended_micro_actions):
|
| 821 |
todays_micro_action = self.recommended_micro_actions.pop(0)
|
| 822 |
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) **"
|
| 823 |
elif theme == "OPEN_DISCUSSION_STATE":
|
| 824 |
+
formatted_message = OPEN_DISCUSSION_STATE.format(self.get_current_goal(), day, len(self.growth_plan.array))
|
| 825 |
if len(self.other_focusses):
|
| 826 |
focus = self.other_focusses.pop(0)
|
| 827 |
formatted_message += f"\n\n** IMPORTANT: Today, focus the discussion on: {focus.content}, which they discussed during their growth guide session (let the user know we are bringing it up because of this) **"
|
| 828 |
elif theme == "PROGRESS_SUMMARY_STATE":
|
| 829 |
+
formatted_message = PROGRESS_SUMMARY_STATE.format(self.get_current_goal(), day, len(self.growth_plan.array))
|
| 830 |
elif theme == "FINAL_SUMMARY_STATE":
|
| 831 |
+
formatted_message = FINAL_SUMMARY_STATE.format(self.get_current_goal(), day, len(self.growth_plan.array))
|
| 832 |
elif theme == "EDUCATION_STATE":
|
| 833 |
+
formatted_message = EDUCATION_STATE.format(self.get_current_goal(), day, len(self.growth_plan.array))
|
| 834 |
elif theme == "FOLLUP_ACTION_STATE":
|
| 835 |
reminder_message = "\n".join([f"{i+1}. {reminder}" for i, reminder in enumerate(reminders)]) if reminders else "User has no postponed micro-actions"
|
| 836 |
+
formatted_message = FOLLUP_ACTION_STATE.format(self.get_current_goal(), day, len(self.growth_plan.array), reminder_message)
|
| 837 |
elif theme == "FUNFACT_STATE":
|
| 838 |
topics = ["Fun Fact about the User's Goal", "How Personality Type is affecting/shaping their behaviour towards the goal", "How Love Language may impact and be relevant toward the goal"]
|
| 839 |
randomized_topic = random.choice(topics)
|
| 840 |
+
formatted_message = FUNFACT_STATE.format(self.get_current_goal(), day, len(self.growth_plan.array), randomized_topic)
|
| 841 |
+
|
| 842 |
# prompt = f"""** It is a new day: {date} **
|
| 843 |
# Additional System Instruction:
|
| 844 |
# - Remember all of the user's personal information. Use this information to be as personalised as possible when conversing by including it in your responses where relevant.
|
|
|
|
| 852 |
# """
|
| 853 |
|
| 854 |
prompt = f"""** It is a new day: {date} ({day}) 10:00:00 **
|
|
|
|
|
|
|
|
|
|
| 855 |
Additional System Instruction:
|
| 856 |
+
** Always remember to incorporate your personality (based on your persona) into all of your responses. **
|
| 857 |
1. Focus on giving more wisdom than questions:
|
| 858 |
- Provide assertive guidance, encouragement, validation, and different viewpoints.
|
| 859 |
- Be critical and challenge the user's arguments as needed.
|
|
|
|
| 874 |
- Enrich content with user information.
|
| 875 |
- Avoid being a "boring" coach with generic questions or advice.
|
| 876 |
|
| 877 |
+
6. Channel the energy, wisdom, and mindset of your persona:
|
| 878 |
+
- Reiterate your famous sayings.
|
| 879 |
+
- Explain your thinking philosophy in a natural, casual conversational tone (not like a lecture).
|
| 880 |
|
| 881 |
7. You may greet the user by name on a new day, but no need to use their name in every message.
|
| 882 |
|
|
|
|
| 890 |
if theme == "MICRO_ACTION_STATE":
|
| 891 |
# check for any recommended microactions
|
| 892 |
logger.info(f"Checking for recommended micro actions", extra={"user_id": self.user_id, "endpoint": "do_theme"})
|
| 893 |
+
micro_action = UserDataItem(role="assistant", area=self.get_current_goal(full=True).area, content=response['content'], user_id=self.user_id, status="PENDING", created_at=pd.Timestamp.now(tz='UTC').strftime("%d-%m-%Y %a %H:%M:%S"), updated_at=pd.Timestamp.now(tz='UTC').strftime("%d-%m-%Y %a %H:%M:%S"))
|
| 894 |
logger.info(f"Recommended Micro Action: {micro_action}", extra={"user_id": self.user_id, "endpoint": "do_theme"})
|
| 895 |
self.micro_actions.append(micro_action)
|
| 896 |
|
|
|
|
| 910 |
if self.reminders is not None and len(self.reminders):
|
| 911 |
# remove all reminders which 'recurrence' is 'once' or 'action' is 'delete' or the date is < today
|
| 912 |
# this is to ensure that only reminders with recurrence and future reminder are kept
|
| 913 |
+
now_utc = pd.Timestamp.now(tz='UTC')
|
| 914 |
+
self.reminders = [reminder for reminder in self.reminders if not (reminder['action'] == 'delete' or (reminder['recurrence'] in ['once', 'postponed'] and reminder['timestamp'].tz_convert('UTC') < now_utc))]
|
| 915 |
logger.info(f"Active Reminders: {self.reminders}", extra={"user_id": self.user_id, "endpoint": "user_change_date"})
|
| 916 |
|
| 917 |
## ADD POINT FOR CHANGE DATE
|
| 918 |
if self.growth_plan.current()['day'] == 7:
|
| 919 |
self.add_life_score_point(variable = self.get_current_goal(full=True).area, points_added = 5, notes = "Reaching Day 7")
|
| 920 |
+
self.add_recent_wins(wins = "You have reached Day 7 of your growth journey!", context = 'Growth journey is a 14-day coaching plan')
|
| 921 |
elif self.growth_plan.current()['day'] == 14:
|
| 922 |
self.add_life_score_point(variable = self.get_current_goal(full=True).area, points_added = 10, notes = "Reaching Day 14")
|
| 923 |
+
self.add_recent_wins(wins = "You have finished your growth journey!", context = 'Growth journey is a 14-day coaching plan')
|
| 924 |
|
| 925 |
logger.info(f"Today's action is {action}", extra={"user_id": self.user_id, "endpoint": "user_change_date"})
|
| 926 |
|
|
|
|
| 1031 |
)
|
| 1032 |
|
| 1033 |
try:
|
| 1034 |
+
current_time = datetime.now(timezone.utc).strftime("%d-%m-%Y %a %H:%M:%S")
|
| 1035 |
|
| 1036 |
response = self.client.beta.chat.completions.parse(
|
| 1037 |
model="gpt-4o",
|
|
|
|
| 1071 |
The user has a current goal: {self.get_current_goal()}
|
| 1072 |
The user provided a new goal: {goal_text}
|
| 1073 |
|
| 1074 |
+
Determine if the new goal is inside the scope of the current goal or if it's outside the scope.
|
| 1075 |
+
If it's inside the scope, respond **exactly** with the current goal, and set same_or_not == True
|
| 1076 |
+
If it's outside the scope and related, respond with a merged goal (from the current and new goal) with larger scope, and set same_or_not == False
|
| 1077 |
+
If it's outside the scope and not related, respond with the new goal, and set same_or_not == False
|
| 1078 |
+
Note: You may paraphase the merged goal to be more succinct.
|
| 1079 |
+
|
| 1080 |
Your response will be the final goal. You will also need to determine the area of this
|
| 1081 |
final goal by choosing one of these areas that suits the final goal:
|
| 1082 |
"Personal Growth", "Career Growth", "Relationship", "Mental Well-Being", "Health and Wellness"
|
|
|
|
| 1087 |
goal: str (the final goal),
|
| 1088 |
area: str (the area of the goal)
|
| 1089 |
}}
|
| 1090 |
+
|
| 1091 |
+
## Example 1 (Inside the scope):
|
| 1092 |
+
The user has a current goal: to spend at least 30 minutes exercising every day
|
| 1093 |
+
The user provided a new goal: to do short exercise every day
|
| 1094 |
+
Your verdict: inside the scope
|
| 1095 |
+
Your output:
|
| 1096 |
+
{{
|
| 1097 |
+
same_or_not: True,
|
| 1098 |
+
goal: "to spend at least 30 minutes exercising every day"
|
| 1099 |
+
area: "Health and Wellness"
|
| 1100 |
+
}}
|
| 1101 |
+
|
| 1102 |
+
## Example 2 (Outside the scope, still related):
|
| 1103 |
+
The user has a current goal: to spend at least 30 minutes exercising every day
|
| 1104 |
+
The user provided a new goal: to exercise and have a balanced meal plan
|
| 1105 |
+
Your verdict: outside the scope, still related
|
| 1106 |
+
Your output:
|
| 1107 |
+
{{
|
| 1108 |
+
same_or_not: False,
|
| 1109 |
+
goal: "to exercise at least 30 minutes every day, together with a balanced meal plan"
|
| 1110 |
+
area: "Health and Wellness"
|
| 1111 |
+
}}
|
| 1112 |
+
|
| 1113 |
+
## Example 3 (Outside the scope, not related):
|
| 1114 |
+
The user has a current goal: to spend at least 30 minutes exercising every day
|
| 1115 |
+
The user provided a new goal: to have a better relationship with friends
|
| 1116 |
+
Your verdict: outside the scope, not related
|
| 1117 |
+
Your output:
|
| 1118 |
+
{{
|
| 1119 |
+
same_or_not: False,
|
| 1120 |
+
goal: "to have a better relationship with friends"
|
| 1121 |
+
area: "Relationship"
|
| 1122 |
+
}}
|
| 1123 |
+
|
| 1124 |
"""
|
| 1125 |
|
| 1126 |
response = self.client.chat.completions.create(
|
|
|
|
| 1182 |
def update_micro_action_status(self, completed_micro_action):
|
| 1183 |
if completed_micro_action:
|
| 1184 |
self.micro_actions[-1].status = "COMPLETE"
|
| 1185 |
+
self.micro_actions[-1].updated_at = pd.Timestamp.now(tz='UTC').strftime("%d-%m-%Y %a %H:%M:%S")
|
| 1186 |
|
| 1187 |
num_of_micro_actions_completed = sum(1 for item in self.micro_actions if item.status == 'COMPLETE')
|
| 1188 |
|
| 1189 |
if (num_of_micro_actions_completed in (1,3,5)) or (num_of_micro_actions_completed % 10 == 0 and num_of_micro_actions_completed != 0):
|
| 1190 |
self.add_life_score_point(variable = self.get_current_goal(full=True).area, points_added = 10, notes = f"Completing the {num_of_micro_actions_completed}-th micro-action")
|
| 1191 |
+
self.add_recent_wins(wins = "You have completed a micro action!", context= self.micro_actions[-1]['content'])
|
| 1192 |
|
| 1193 |
def trigger_deep_reflection_point(self, area_of_deep_reflection):
|
| 1194 |
if len(area_of_deep_reflection)>0:
|
| 1195 |
for area in area_of_deep_reflection:
|
| 1196 |
self.add_life_score_point(variable = area, points_added = 5, notes = f"Doing a deep reflection about {area}")
|
| 1197 |
+
self.add_recent_wins(wins = f"You have done a deep reflection about your {area}!", context = 'Deep reflection')
|
| 1198 |
|
| 1199 |
def add_point_for_booking(self):
|
| 1200 |
self.add_life_score_point(variable = self.get_current_goal(full=True).area, points_added = 5, notes = "Booking a GG session")
|
| 1201 |
+
self.add_recent_wins(wins = "You have booked a Growth Guide session!", context = "Growth Guide is a life coach")
|
| 1202 |
|
| 1203 |
def add_point_for_completing_session(self):
|
| 1204 |
self.add_life_score_point(variable = self.get_current_goal(full=True).area, points_added = 20, notes = "Completing a GG session")
|
| 1205 |
+
self.add_recent_wins(wins = "You have completed a Growth Guide session!", context = "Growth Guide is a life coach")
|
| 1206 |
|
| 1207 |
def build_ourcoach_report(self, overview, action_plan, gg_session_notes):
|
| 1208 |
logger.info(f"Building ourcoach report", extra={"user_id": self.user_id, "endpoint": "build_ourcoach_report"})
|
app/utils.py
CHANGED
|
@@ -15,7 +15,7 @@ import psycopg2
|
|
| 15 |
from psycopg2 import sql
|
| 16 |
import os
|
| 17 |
from dotenv import load_dotenv
|
| 18 |
-
import datetime
|
| 19 |
import threading
|
| 20 |
import pickle # Replace dill with pickle
|
| 21 |
from cachetools import TTLCache
|
|
@@ -419,19 +419,21 @@ def get_user_summary(user_id):
|
|
| 419 |
|
| 420 |
**Objective**: Guide the user on what to discuss with the Growth Guide, providing actionable advice and highlighting key areas to focus on during their session, covering the five key areas.
|
| 421 |
|
|
|
|
|
|
|
| 422 |
**Format**:
|
| 423 |
|
| 424 |
Structure the brief with the following sections, and output it as a JSON object with these keys:
|
| 425 |
|
| 426 |
-
- **reflect**:
|
| 427 |
|
| 428 |
-
- **recall_successes**:
|
| 429 |
|
| 430 |
-
- **identify_challenges**:
|
| 431 |
|
| 432 |
- **set_goals**: Ask the user to decide what they hope to achieve from the session and how improvements in each area will impact their life.
|
| 433 |
|
| 434 |
-
- **additional_tips**:
|
| 435 |
|
| 436 |
---
|
| 437 |
|
|
@@ -534,23 +536,23 @@ def get_user_summary(user_id):
|
|
| 534 |
"users_growth_guide_preparation_brief": [
|
| 535 |
{
|
| 536 |
"key": "reflect",
|
| 537 |
-
"value": "
|
| 538 |
},
|
| 539 |
{
|
| 540 |
"key": "recall_successes",
|
| 541 |
-
"value": "
|
| 542 |
},
|
| 543 |
{
|
| 544 |
"key": "identify_challenges",
|
| 545 |
-
"value": "
|
| 546 |
},
|
| 547 |
{
|
| 548 |
"key": "set_goals",
|
| 549 |
-
"value": "
|
| 550 |
},
|
| 551 |
{
|
| 552 |
"key": "additional_tips",
|
| 553 |
-
"value": "
|
| 554 |
}
|
| 555 |
],
|
| 556 |
"30_minute_coaching_session_script": {
|
|
@@ -983,7 +985,7 @@ def get_user_life_status(user_id):
|
|
| 983 |
"relationship": user.relationship_score
|
| 984 |
}
|
| 985 |
# Get current goal
|
| 986 |
-
current_goal =
|
| 987 |
# Get life score achievements in list
|
| 988 |
recent_wins = user.recent_wins
|
| 989 |
# Combine everything
|
|
@@ -1163,7 +1165,7 @@ def add_growth_guide_session(user_id, session_id, coach_id, session_started_at,
|
|
| 1163 |
INSERT INTO {table} (booking_id, coach_id, session_started_at, user_id, updated_at, gg_report, ourcoach_summary, created_at, zoom_ai_summary)
|
| 1164 |
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)
|
| 1165 |
""").format(table=sql.Identifier('public', 'user_notes'))
|
| 1166 |
-
current_time = datetime.
|
| 1167 |
cursor.execute(query, (
|
| 1168 |
session_id,
|
| 1169 |
coach_id,
|
|
@@ -1224,7 +1226,7 @@ def download_file_from_s3(filename, bucket):
|
|
| 1224 |
s3_client = session.client('s3')
|
| 1225 |
with open(file_path, 'wb') as f:
|
| 1226 |
## Upload to Production Folder
|
| 1227 |
-
s3_client.download_fileobj(bucket, f"
|
| 1228 |
logger.info(f"File {filename} downloaded successfully from S3", extra={'user_id': user_id, 'endpoint': function_name})
|
| 1229 |
return True
|
| 1230 |
except Exception as e:
|
|
@@ -1320,7 +1322,7 @@ def upload_mementos_to_db(user_id):
|
|
| 1320 |
data.get('location', ''),
|
| 1321 |
data.get('recurrence', ''),
|
| 1322 |
data.get('context', ''),
|
| 1323 |
-
datetime.
|
| 1324 |
pd.to_datetime(data.get('follow_up_on', ''))
|
| 1325 |
]
|
| 1326 |
cursor.execute(base_query, memento_data)
|
|
@@ -1399,7 +1401,7 @@ def print_log(level, message, **kwargs):
|
|
| 1399 |
print_log("INFO", "User logged in", user_id=123, action="login")
|
| 1400 |
"""
|
| 1401 |
log_entry = {
|
| 1402 |
-
"timestamp": datetime.
|
| 1403 |
"level": level,
|
| 1404 |
"message": message,
|
| 1405 |
}
|
|
|
|
| 15 |
from psycopg2 import sql
|
| 16 |
import os
|
| 17 |
from dotenv import load_dotenv
|
| 18 |
+
from datetime import datetime, timezone
|
| 19 |
import threading
|
| 20 |
import pickle # Replace dill with pickle
|
| 21 |
from cachetools import TTLCache
|
|
|
|
| 419 |
|
| 420 |
**Objective**: Guide the user on what to discuss with the Growth Guide, providing actionable advice and highlighting key areas to focus on during their session, covering the five key areas.
|
| 421 |
|
| 422 |
+
**ALWAYS** be succinct, valuable and personalized!
|
| 423 |
+
|
| 424 |
**Format**:
|
| 425 |
|
| 426 |
Structure the brief with the following sections, and output it as a JSON object with these keys:
|
| 427 |
|
| 428 |
+
- **reflect**: Give a succinct, valuable and personalized advice to the user to consider what each focus area means to them and which aspects they want to improve.
|
| 429 |
|
| 430 |
+
- **recall_successes**: Give a succinct, valuable and personalized prompt to the user to think of times when they effectively managed or improved in the five key areas, and what strategies worked for them then.
|
| 431 |
|
| 432 |
+
- **identify_challenges**: Give a succinct, valuable and personalized advice to the user to be ready to discuss any obstacles they're facing in each area, and to consider possible solutions or resources that might help.
|
| 433 |
|
| 434 |
- **set_goals**: Ask the user to decide what they hope to achieve from the session and how improvements in each area will impact their life.
|
| 435 |
|
| 436 |
+
- **additional_tips**: Give a succinct, valuable and personalized practical advice for the session, such as choosing a quiet space, having materials ready, and being open to sharing thoughts honestly.
|
| 437 |
|
| 438 |
---
|
| 439 |
|
|
|
|
| 536 |
"users_growth_guide_preparation_brief": [
|
| 537 |
{
|
| 538 |
"key": "reflect",
|
| 539 |
+
"value": "Reflect on what career growth means to you and the goals you’re striving for."
|
| 540 |
},
|
| 541 |
{
|
| 542 |
"key": "recall_successes",
|
| 543 |
+
"value": "Recall moments when you successfully navigated challenges in your career or relationships—what worked"
|
| 544 |
},
|
| 545 |
{
|
| 546 |
"key": "identify_challenges",
|
| 547 |
+
"value": "Think about any current obstacles and possible ways to overcome them"
|
| 548 |
},
|
| 549 |
{
|
| 550 |
"key": "set_goals",
|
| 551 |
+
"value": "Define what you want to achieve from this session and how those changes could impact your life."
|
| 552 |
},
|
| 553 |
{
|
| 554 |
"key": "additional_tips",
|
| 555 |
+
"value": "Prepare by choosing a quiet space, having a notebook ready, and being open to sharing honestly."
|
| 556 |
}
|
| 557 |
],
|
| 558 |
"30_minute_coaching_session_script": {
|
|
|
|
| 985 |
"relationship": user.relationship_score
|
| 986 |
}
|
| 987 |
# Get current goal
|
| 988 |
+
current_goal = '' if not user.goal else user.goal[-1].content
|
| 989 |
# Get life score achievements in list
|
| 990 |
recent_wins = user.recent_wins
|
| 991 |
# Combine everything
|
|
|
|
| 1165 |
INSERT INTO {table} (booking_id, coach_id, session_started_at, user_id, updated_at, gg_report, ourcoach_summary, created_at, zoom_ai_summary)
|
| 1166 |
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)
|
| 1167 |
""").format(table=sql.Identifier('public', 'user_notes'))
|
| 1168 |
+
current_time = datetime.now(timezone.utc)
|
| 1169 |
cursor.execute(query, (
|
| 1170 |
session_id,
|
| 1171 |
coach_id,
|
|
|
|
| 1226 |
s3_client = session.client('s3')
|
| 1227 |
with open(file_path, 'wb') as f:
|
| 1228 |
## Upload to Production Folder
|
| 1229 |
+
s3_client.download_fileobj(bucket, f"staging/users/{filename}", f)
|
| 1230 |
logger.info(f"File {filename} downloaded successfully from S3", extra={'user_id': user_id, 'endpoint': function_name})
|
| 1231 |
return True
|
| 1232 |
except Exception as e:
|
|
|
|
| 1322 |
data.get('location', ''),
|
| 1323 |
data.get('recurrence', ''),
|
| 1324 |
data.get('context', ''),
|
| 1325 |
+
datetime.now(timezone.utc),
|
| 1326 |
pd.to_datetime(data.get('follow_up_on', ''))
|
| 1327 |
]
|
| 1328 |
cursor.execute(base_query, memento_data)
|
|
|
|
| 1401 |
print_log("INFO", "User logged in", user_id=123, action="login")
|
| 1402 |
"""
|
| 1403 |
log_entry = {
|
| 1404 |
+
"timestamp": datetime.utcnow().isoformat() + "Z",
|
| 1405 |
"level": level,
|
| 1406 |
"message": message,
|
| 1407 |
}
|