Spaces:
Sleeping
Sleeping
Persona Integration & Modified User Context
#12
by
BMCVRN - 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 +1 -1
- app/conversation_manager.py +10 -1
- app/flows.py +9 -5
- app/main.py +28 -6
- app/user.py +41 -12
- app/utils.py +22 -13
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
|
@@ -382,7 +382,7 @@ class Assistant:
|
|
| 382 |
return run, just_finished_intro, message
|
| 383 |
|
| 384 |
elif run.status == 'failed':
|
| 385 |
-
raise OpenAIRequestError(user_id=self.cm.user.
|
| 386 |
|
| 387 |
elif run.status == 'requires_action':
|
| 388 |
reccursion = 0
|
|
|
|
| 382 |
return run, just_finished_intro, message
|
| 383 |
|
| 384 |
elif run.status == 'failed':
|
| 385 |
+
raise OpenAIRequestError(user_id=self.cm.user.user_id, message="Run failed", run_id=run.id)
|
| 386 |
|
| 387 |
elif run.status == 'requires_action':
|
| 388 |
reccursion = 0
|
app/conversation_manager.py
CHANGED
|
@@ -9,8 +9,12 @@ from app.exceptions import BaseOurcoachException, ConversationManagerError, Open
|
|
| 9 |
from datetime import datetime
|
| 10 |
|
| 11 |
import dotenv
|
|
|
|
|
|
|
| 12 |
dotenv.load_dotenv()
|
| 13 |
|
|
|
|
|
|
|
| 14 |
logger = logging.getLogger(__name__)
|
| 15 |
|
| 16 |
def get_current_datetime():
|
|
@@ -62,12 +66,17 @@ class ConversationManager:
|
|
| 62 |
thread = self.client.beta.threads.create()
|
| 63 |
self.system_message = self.add_message_to_thread(thread.id, "assistant",
|
| 64 |
f"""
|
|
|
|
|
|
|
|
|
|
|
|
|
| 65 |
You are coaching:
|
| 66 |
\n\n{user_interaction_guidelines}\n\n\
|
| 67 |
Be mindful of this information at all times in order to
|
| 68 |
be as personalised as possible when conversing. Ensure to
|
| 69 |
follow the conversation guidelines and flow templates. Use the
|
| 70 |
current state of the conversation to adhere to the flow. Do not let the user know about any transitions.\n\n
|
|
|
|
| 71 |
** Today is {self.state['date']}.\n\n **
|
| 72 |
** You are now in the INTRODUCTION STATE. **
|
| 73 |
""")
|
|
@@ -185,7 +194,7 @@ class ConversationManager:
|
|
| 185 |
# OPENAI LIMITATION: Can only attach a maximum of 32 messages when creating a new thread
|
| 186 |
messages = self._get_current_thread_history(remove_system_message=False)
|
| 187 |
if len(messages) >= 29:
|
| 188 |
-
messages = [{"content": """ Remember who you are coaching.
|
| 189 |
Be mindful of this information at all times in order to
|
| 190 |
be as personalised as possible when conversing. Ensure to
|
| 191 |
follow the conversation guidelines and flow provided.""", "role":"assistant"}] + messages[-29:]
|
|
|
|
| 9 |
from datetime import datetime
|
| 10 |
|
| 11 |
import dotenv
|
| 12 |
+
|
| 13 |
+
from app.utils import id_to_persona
|
| 14 |
dotenv.load_dotenv()
|
| 15 |
|
| 16 |
+
OURCOACH_DASHBOARD_URL = os.getenv("OURCOACH_DASHBOARD_URL")
|
| 17 |
+
|
| 18 |
logger = logging.getLogger(__name__)
|
| 19 |
|
| 20 |
def get_current_datetime():
|
|
|
|
| 66 |
thread = self.client.beta.threads.create()
|
| 67 |
self.system_message = self.add_message_to_thread(thread.id, "assistant",
|
| 68 |
f"""
|
| 69 |
+
You are:
|
| 70 |
+
{id_to_persona(self.user.asst_id)}, always adhere to your choosen persona by incorporating it conversationally.
|
| 71 |
+
You represent a coach at ourcoach. You may refer to you knowledgebase for all information related to ourcoach.
|
| 72 |
+
-------------------------------------------
|
| 73 |
You are coaching:
|
| 74 |
\n\n{user_interaction_guidelines}\n\n\
|
| 75 |
Be mindful of this information at all times in order to
|
| 76 |
be as personalised as possible when conversing. Ensure to
|
| 77 |
follow the conversation guidelines and flow templates. Use the
|
| 78 |
current state of the conversation to adhere to the flow. Do not let the user know about any transitions.\n\n
|
| 79 |
+
Whenever you reference the dashboard or Revelation Dashboard, inlcue the link: {OURCOACH_DASHBOARD_URL} .
|
| 80 |
** Today is {self.state['date']}.\n\n **
|
| 81 |
** You are now in the INTRODUCTION STATE. **
|
| 82 |
""")
|
|
|
|
| 194 |
# OPENAI LIMITATION: Can only attach a maximum of 32 messages when creating a new thread
|
| 195 |
messages = self._get_current_thread_history(remove_system_message=False)
|
| 196 |
if len(messages) >= 29:
|
| 197 |
+
messages = [{"content": """ Remember who you are and who you are coaching.
|
| 198 |
Be mindful of this information at all times in order to
|
| 199 |
be as personalised as possible when conversing. Ensure to
|
| 200 |
follow the conversation guidelines and flow provided.""", "role":"assistant"}] + messages[-29:]
|
app/flows.py
CHANGED
|
@@ -483,11 +483,14 @@ Objective: To summarize the user's progress and achievements during the coaching
|
|
| 483 |
Users Goal: {{}}
|
| 484 |
The user is currently on day {{}}/{{}} of their journey.
|
| 485 |
|
|
|
|
|
|
|
|
|
|
| 486 |
## ** GUIDELINE ** :
|
| 487 |
|
| 488 |
## What Makes a Good Interaction:
|
| 489 |
|
| 490 |
-
- Highlight the user's progress and achievements precisely and concisely. Use bullet points to list down your items.
|
| 491 |
|
| 492 |
- Explain to the user that coaching is a continuous journey, so the user has the option to either continue with the same goal or create a new plan.
|
| 493 |
|
|
@@ -505,13 +508,14 @@ The user is currently on day {{}}/{{}} of their journey.
|
|
| 505 |
|
| 506 |
- Congratulate the user for completing the growth plan until the last day (mention the current day, e.g. day 4)
|
| 507 |
|
| 508 |
-
- Highlight the user's progress and achievements in bullet points. And tell them to check out their progress in the Revelation Dashboard here: https://app.staging.ourcoach.ai/
|
| 509 |
-
|
| 510 |
-
- Ask the user whether they want to meet their Growth Guide to plan what's next! (Only ask this question first)
|
| 511 |
|
|
|
|
|
|
|
|
|
|
| 512 |
- Wait for the user's response.
|
| 513 |
|
| 514 |
-
- **IF** the user
|
| 515 |
|
| 516 |
Amazing! 🎉
|
| 517 |
|
|
|
|
| 483 |
Users Goal: {{}}
|
| 484 |
The user is currently on day {{}}/{{}} of their journey.
|
| 485 |
|
| 486 |
+
User's Last Growth Guide Session:
|
| 487 |
+
{{}}
|
| 488 |
+
|
| 489 |
## ** GUIDELINE ** :
|
| 490 |
|
| 491 |
## What Makes a Good Interaction:
|
| 492 |
|
| 493 |
+
- Highlight the user's progress and achievements precisely and concisely. IF the user has completed a growth guide session (see above), incorporate it into your response and reference that it was acheived during their growth guide session. Use bullet points to list down your items.
|
| 494 |
|
| 495 |
- Explain to the user that coaching is a continuous journey, so the user has the option to either continue with the same goal or create a new plan.
|
| 496 |
|
|
|
|
| 508 |
|
| 509 |
- Congratulate the user for completing the growth plan until the last day (mention the current day, e.g. day 4)
|
| 510 |
|
| 511 |
+
- Highlight the user's progress and achievements in bullet points. IF the user has completed a growth guide session (see above), incorporate it into your response and reference that it was acheived during their growth guide session. And tell them to check out their progress in the Revelation Dashboard here: https://app.staging.ourcoach.ai/
|
|
|
|
|
|
|
| 512 |
|
| 513 |
+
- IF the user has not completed a growth guide session yet (see above), encourage the user to book a Growth Guide session and explain its benefits. Really upsell this by being like a Growth Guide salesman!
|
| 514 |
+
- ELSE IF the user has booked a growth guide session (see above), tell them you hope it went well and they found it beneficial and let the use know that they could also book another via their Revelation Dashboard: https://app.staging.ourcoach.ai/
|
| 515 |
+
|
| 516 |
- Wait for the user's response.
|
| 517 |
|
| 518 |
+
- **IF** the user says they want to book a growth guide session, you reply with this message:
|
| 519 |
|
| 520 |
Amazing! 🎉
|
| 521 |
|
app/main.py
CHANGED
|
@@ -257,8 +257,6 @@ class LoggingMiddleware(BaseHTTPMiddleware):
|
|
| 257 |
raise
|
| 258 |
|
| 259 |
# OpenAI Client
|
| 260 |
-
# GENERAL_ASSISTANT = os.getenv('OPENAI_GENERAL_ASSISTANT')
|
| 261 |
-
GENERAL_ASSISTANT = "asst_vnucWWELJlCWadfAARwyKkCW"
|
| 262 |
|
| 263 |
# Initialize Logging (optional)
|
| 264 |
# logging.basicConfig(filename='app.log', level=logging.INFO)
|
|
@@ -485,7 +483,7 @@ async def migrate_user(
|
|
| 485 |
|
| 486 |
with open(user_file, 'rb') as f:
|
| 487 |
old_user_object = pickle.load(f)
|
| 488 |
-
user = User(request.user_id, old_user_object.user_info, client,
|
| 489 |
user.conversations.current_thread = old_user_object.conversations.current_thread
|
| 490 |
user.conversations.intro_done = True
|
| 491 |
user.done_first_reflection = old_user_object.done_first_reflection
|
|
@@ -718,8 +716,29 @@ async def create_user(
|
|
| 718 |
if os.path.exists(f'users/data/{request.user_id}.pkl'):
|
| 719 |
return {"message": f"[OK] User already exists: {request.user_id}"}
|
| 720 |
|
| 721 |
-
user_info,
|
| 722 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 723 |
folder_path = os.path.join("mementos", "to_upload", request.user_id)
|
| 724 |
os.makedirs(folder_path, exist_ok=True)
|
| 725 |
|
|
@@ -876,7 +895,10 @@ async def get_summary_by_id(
|
|
| 876 |
):
|
| 877 |
print_log("INFO", "Getting user's summary", extra={"user_id": user_id, "endpoint": "/get_user_summary"})
|
| 878 |
logger.info("Getting user's summary", extra={"user_id": user_id, "endpoint": "/get_user_summary"})
|
| 879 |
-
|
|
|
|
|
|
|
|
|
|
| 880 |
print_log("INFO", "Successfully generated summary", extra={"user_id": user_id, "endpoint": "/get_user_summary"})
|
| 881 |
logger.info("Successfully generated summary", extra={"user_id": user_id, "endpoint": "/get_user_summary"})
|
| 882 |
return user_summary
|
|
|
|
| 257 |
raise
|
| 258 |
|
| 259 |
# OpenAI Client
|
|
|
|
|
|
|
| 260 |
|
| 261 |
# Initialize Logging (optional)
|
| 262 |
# logging.basicConfig(filename='app.log', level=logging.INFO)
|
|
|
|
| 483 |
|
| 484 |
with open(user_file, 'rb') as f:
|
| 485 |
old_user_object = pickle.load(f)
|
| 486 |
+
user = User(request.user_id, old_user_object.user_info, client, old_user_object.asst_id)
|
| 487 |
user.conversations.current_thread = old_user_object.conversations.current_thread
|
| 488 |
user.conversations.intro_done = True
|
| 489 |
user.done_first_reflection = old_user_object.done_first_reflection
|
|
|
|
| 716 |
if os.path.exists(f'users/data/{request.user_id}.pkl'):
|
| 717 |
return {"message": f"[OK] User already exists: {request.user_id}"}
|
| 718 |
|
| 719 |
+
user_info, persona = get_user_info(request.user_id)
|
| 720 |
+
# Persona is one of ["Coach Steve", "Coach Aris", "Coach Teresa"]
|
| 721 |
+
# we map each of the above to assistant_ids = ["asst_mUm6MBcW544p1iVov9mwIC96", "asst_4WcktKgYdDnXA1QUlWvrNfWV", "asst_4UVkFK6r2pbz6NK6kNzG4sTW"]
|
| 722 |
+
persona_to_assistant = {
|
| 723 |
+
"Coach Steve": "asst_mUm6MBcW544p1iVov9mwIC96",
|
| 724 |
+
"Coach Aris": "asst_4WcktKgYdDnXA1QUlWvrNfWV",
|
| 725 |
+
"Coach Teresa": "asst_4UVkFK6r2pbz6NK6kNzG4sTW"
|
| 726 |
+
}
|
| 727 |
+
|
| 728 |
+
if persona not in persona_to_assistant:
|
| 729 |
+
logger.warning(f"Invalid persona: {persona}, defaulting to: Coach Steve", extra={"user_id": request.user_id, "endpoint": "/create_user"})
|
| 730 |
+
# For testing we default to steve
|
| 731 |
+
persona = "Coach Steve"
|
| 732 |
+
# raise FastAPIError(
|
| 733 |
+
# message="Invalid persona",
|
| 734 |
+
# e="Persona must be one of ['Coach Steve', 'Coach Aris', 'Coach Teresa']"
|
| 735 |
+
# )
|
| 736 |
+
|
| 737 |
+
selected_persona = persona_to_assistant[persona]
|
| 738 |
+
|
| 739 |
+
logger.info(f"Creating user with persona {persona}:{selected_persona}", extra={"user_id": request.user_id, "endpoint": "/create_user"})
|
| 740 |
+
|
| 741 |
+
user = User(request.user_id, user_info, client, selected_persona)
|
| 742 |
folder_path = os.path.join("mementos", "to_upload", request.user_id)
|
| 743 |
os.makedirs(folder_path, exist_ok=True)
|
| 744 |
|
|
|
|
| 895 |
):
|
| 896 |
print_log("INFO", "Getting user's summary", extra={"user_id": user_id, "endpoint": "/get_user_summary"})
|
| 897 |
logger.info("Getting user's summary", extra={"user_id": user_id, "endpoint": "/get_user_summary"})
|
| 898 |
+
|
| 899 |
+
# NOTE: This call will also update the users recommended topics to discuss with GG.
|
| 900 |
+
# This is so that the AI response will align with the dashboard.
|
| 901 |
+
user_summary = get_user_summary(user_id, update_rec_topics=True)
|
| 902 |
print_log("INFO", "Successfully generated summary", extra={"user_id": user_id, "endpoint": "/get_user_summary"})
|
| 903 |
logger.info("Successfully generated summary", extra={"user_id": user_id, "endpoint": "/get_user_summary"})
|
| 904 |
return user_summary
|
app/user.py
CHANGED
|
@@ -19,7 +19,7 @@ from app.flows import FINAL_SUMMARY_STATE, FINAL_SUMMARY_STATE, MICRO_ACTION_STA
|
|
| 19 |
from pydantic import BaseModel
|
| 20 |
from datetime import datetime
|
| 21 |
|
| 22 |
-
from app.utils import generate_uuid, update_growth_guide_summary
|
| 23 |
|
| 24 |
import dotenv
|
| 25 |
import re
|
|
@@ -97,7 +97,7 @@ class User:
|
|
| 97 |
},
|
| 98 |
{
|
| 99 |
"day": 3,
|
| 100 |
-
"coachingTheme": "
|
| 101 |
},
|
| 102 |
{
|
| 103 |
"day": 4,
|
|
@@ -107,8 +107,7 @@ class User:
|
|
| 107 |
"day": 5,
|
| 108 |
"coachingTheme": "FINAL_SUMMARY_STATE"
|
| 109 |
}
|
| 110 |
-
]
|
| 111 |
-
}
|
| 112 |
|
| 113 |
|
| 114 |
self.growth_plan = CircularQueue(array=growth_plan['growthPlan'], user_id=self.user_id)
|
|
@@ -189,7 +188,7 @@ class User:
|
|
| 189 |
def add_recent_wins(self, wins, context = None):
|
| 190 |
prompt = f"""
|
| 191 |
## Role
|
| 192 |
-
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
|
| 193 |
|
| 194 |
```json
|
| 195 |
{{
|
|
@@ -206,7 +205,7 @@ class User:
|
|
| 206 |
Output:
|
| 207 |
```
|
| 208 |
{{
|
| 209 |
-
achievement_message: You
|
| 210 |
}}
|
| 211 |
```
|
| 212 |
|
|
@@ -630,7 +629,10 @@ class User:
|
|
| 630 |
elif theme == "PROGRESS_SUMMARY_STATE":
|
| 631 |
formatted_message = PROGRESS_SUMMARY_STATE.format(self.get_current_goal(), day, len(self.growth_plan.array))
|
| 632 |
elif theme == "FINAL_SUMMARY_STATE":
|
| 633 |
-
|
|
|
|
|
|
|
|
|
|
| 634 |
elif theme == "EDUCATION_STATE":
|
| 635 |
formatted_message = EDUCATION_STATE.format(self.get_current_goal(), day, len(self.growth_plan.array))
|
| 636 |
elif theme == "FOLLUP_ACTION_STATE":
|
|
@@ -692,6 +694,8 @@ class User:
|
|
| 692 |
|
| 693 |
8. You **MUST** call the process_reminder() function if the user wants to postpone their micro-action
|
| 694 |
|
|
|
|
|
|
|
| 695 |
Today's Theme:
|
| 696 |
{formatted_message}
|
| 697 |
"""
|
|
@@ -794,7 +798,7 @@ class User:
|
|
| 794 |
logger.info(f"Summarizing zoom ai summary", extra={"user_id": self.user_id, "endpoint": "summarize_zoom"})
|
| 795 |
# make an api call to gpt4o to summarize the zoom_ai_summary and produce a text with a focus on the most amount of user insight and info extracted
|
| 796 |
system_prompt = f"""You are an expert at summarizing AI-generated Zoom transcripts concisely, focusing on extracting key user insights to enhance personalization in future interactions. Note that the zoom ai transcript may get the user's name wrong. Replace it with the actual user's name: {self.user_info}. Refer to the coach/guide as 'the Growth Guide'."""
|
| 797 |
-
prompt = f"Please summarize the following AI-generated Zoom transcript **in one short paragraph only** !!, emphasizing the most significant user insights and information:\n\n{zoom_ai_summary}"
|
| 798 |
|
| 799 |
response = self.client.chat.completions.create(
|
| 800 |
model="gpt-4o",
|
|
@@ -802,10 +806,32 @@ class User:
|
|
| 802 |
{"role": "system", "content": system_prompt},
|
| 803 |
{"role": "user", "content": prompt}
|
| 804 |
],
|
| 805 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 806 |
)
|
| 807 |
-
|
| 808 |
-
|
|
|
|
|
|
|
| 809 |
|
| 810 |
@catch_error
|
| 811 |
def _update_user_data(self, data_type, text_input, extra_text=""):
|
|
@@ -996,12 +1022,15 @@ class User:
|
|
| 996 |
if completed_micro_action:
|
| 997 |
self.micro_actions[-1].status = "COMPLETE"
|
| 998 |
self.micro_actions[-1].updated_at = pd.Timestamp.now(tz='UTC').strftime("%d-%m-%Y %a %H:%M:%S")
|
|
|
|
| 999 |
|
| 1000 |
num_of_micro_actions_completed = sum(1 for item in self.micro_actions if item.status == 'COMPLETE')
|
| 1001 |
|
| 1002 |
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):
|
| 1003 |
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")
|
| 1004 |
-
self.add_recent_wins(wins = "You have completed a micro action!", context= self.micro_actions[-1]
|
|
|
|
|
|
|
| 1005 |
|
| 1006 |
@catch_error
|
| 1007 |
def trigger_deep_reflection_point(self, area_of_deep_reflection):
|
|
|
|
| 19 |
from pydantic import BaseModel
|
| 20 |
from datetime import datetime
|
| 21 |
|
| 22 |
+
from app.utils import generate_uuid, get_growth_guide_summary, update_growth_guide_summary
|
| 23 |
|
| 24 |
import dotenv
|
| 25 |
import re
|
|
|
|
| 97 |
},
|
| 98 |
{
|
| 99 |
"day": 3,
|
| 100 |
+
"coachingTheme": "FINAL_SUMMARY_STATE"
|
| 101 |
},
|
| 102 |
{
|
| 103 |
"day": 4,
|
|
|
|
| 107 |
"day": 5,
|
| 108 |
"coachingTheme": "FINAL_SUMMARY_STATE"
|
| 109 |
}
|
| 110 |
+
]}
|
|
|
|
| 111 |
|
| 112 |
|
| 113 |
self.growth_plan = CircularQueue(array=growth_plan['growthPlan'], user_id=self.user_id)
|
|
|
|
| 188 |
def add_recent_wins(self, wins, context = None):
|
| 189 |
prompt = f"""
|
| 190 |
## Role
|
| 191 |
+
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 achievement message/progress notification. The output must be a one sentence short message (less than 15 words) in this JSON output schema:
|
| 192 |
|
| 193 |
```json
|
| 194 |
{{
|
|
|
|
| 205 |
Output:
|
| 206 |
```
|
| 207 |
{{
|
| 208 |
+
achievement_message: You have completed a 10k run!
|
| 209 |
}}
|
| 210 |
```
|
| 211 |
|
|
|
|
| 629 |
elif theme == "PROGRESS_SUMMARY_STATE":
|
| 630 |
formatted_message = PROGRESS_SUMMARY_STATE.format(self.get_current_goal(), day, len(self.growth_plan.array))
|
| 631 |
elif theme == "FINAL_SUMMARY_STATE":
|
| 632 |
+
gg_summary = "<User has not had a Growth Guide session yet>"
|
| 633 |
+
if self.last_gg_session:
|
| 634 |
+
gg_summary = get_growth_guide_summary(self.user_id, self.last_gg_session)
|
| 635 |
+
formatted_message = FINAL_SUMMARY_STATE.format(self.get_current_goal(), day, len(self.growth_plan.array), gg_summary)
|
| 636 |
elif theme == "EDUCATION_STATE":
|
| 637 |
formatted_message = EDUCATION_STATE.format(self.get_current_goal(), day, len(self.growth_plan.array))
|
| 638 |
elif theme == "FOLLUP_ACTION_STATE":
|
|
|
|
| 694 |
|
| 695 |
8. You **MUST** call the process_reminder() function if the user wants to postpone their micro-action
|
| 696 |
|
| 697 |
+
9. When talking about Growth Guide, you must try to upsell the growth guide. Meaning that you are always encouraging the user to book a Growth Guide session and explain it benefits. Be like the Growth Guide's salesman!
|
| 698 |
+
|
| 699 |
Today's Theme:
|
| 700 |
{formatted_message}
|
| 701 |
"""
|
|
|
|
| 798 |
logger.info(f"Summarizing zoom ai summary", extra={"user_id": self.user_id, "endpoint": "summarize_zoom"})
|
| 799 |
# make an api call to gpt4o to summarize the zoom_ai_summary and produce a text with a focus on the most amount of user insight and info extracted
|
| 800 |
system_prompt = f"""You are an expert at summarizing AI-generated Zoom transcripts concisely, focusing on extracting key user insights to enhance personalization in future interactions. Note that the zoom ai transcript may get the user's name wrong. Replace it with the actual user's name: {self.user_info}. Refer to the coach/guide as 'the Growth Guide'."""
|
| 801 |
+
prompt = f"Please summarize the following AI-generated Zoom transcript **in one short paragraph only, around 50 completion tokens maximum** !!, emphasizing the most significant user insights and information:\n\n{zoom_ai_summary}"
|
| 802 |
|
| 803 |
response = self.client.chat.completions.create(
|
| 804 |
model="gpt-4o",
|
|
|
|
| 806 |
{"role": "system", "content": system_prompt},
|
| 807 |
{"role": "user", "content": prompt}
|
| 808 |
],
|
| 809 |
+
response_format = {
|
| 810 |
+
"type": "json_schema",
|
| 811 |
+
"json_schema": {
|
| 812 |
+
"name": "summarized_overview",
|
| 813 |
+
"strict": True,
|
| 814 |
+
"schema": {
|
| 815 |
+
"type": "object",
|
| 816 |
+
"properties": {
|
| 817 |
+
"summary": {
|
| 818 |
+
"type": "string",
|
| 819 |
+
"description": "The summary of the zoom transcript"
|
| 820 |
+
}
|
| 821 |
+
},
|
| 822 |
+
"required": [
|
| 823 |
+
"summary"
|
| 824 |
+
],
|
| 825 |
+
"additionalProperties": False
|
| 826 |
+
}
|
| 827 |
+
}
|
| 828 |
+
},
|
| 829 |
+
temperature=0.5
|
| 830 |
)
|
| 831 |
+
|
| 832 |
+
overview_summary = json.loads(response.choices[0].message.content)['summary']
|
| 833 |
+
logger.info(f"Summary: {overview_summary}", extra={"user_id": self.user_id, "endpoint": "summarize_zoom"})
|
| 834 |
+
return {'overview': overview_summary}
|
| 835 |
|
| 836 |
@catch_error
|
| 837 |
def _update_user_data(self, data_type, text_input, extra_text=""):
|
|
|
|
| 1022 |
if completed_micro_action:
|
| 1023 |
self.micro_actions[-1].status = "COMPLETE"
|
| 1024 |
self.micro_actions[-1].updated_at = pd.Timestamp.now(tz='UTC').strftime("%d-%m-%Y %a %H:%M:%S")
|
| 1025 |
+
logger.info("Micro action status updated, checking number of actions completed...", extra={"user_id": self.user_id, "endpoint": "update_micro_action_status"})
|
| 1026 |
|
| 1027 |
num_of_micro_actions_completed = sum(1 for item in self.micro_actions if item.status == 'COMPLETE')
|
| 1028 |
|
| 1029 |
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):
|
| 1030 |
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")
|
| 1031 |
+
self.add_recent_wins(wins = "You have completed a micro action!", context= self.micro_actions[-1].content)
|
| 1032 |
+
logger.info("Added life score points based on number of actions completed.", extra={"user_id": self.user_id, "endpoint": "update_micro_action_status"})
|
| 1033 |
+
logger.info("Process done.", extra={"user_id": self.user_id, "endpoint": "update_micro_action_status"})
|
| 1034 |
|
| 1035 |
@catch_error
|
| 1036 |
def trigger_deep_reflection_point(self, area_of_deep_reflection):
|
app/utils.py
CHANGED
|
@@ -1,14 +1,13 @@
|
|
| 1 |
import logging
|
| 2 |
import boto3
|
| 3 |
-
from botocore.exceptions import
|
| 4 |
import os
|
| 5 |
from dotenv import load_dotenv
|
| 6 |
-
from fastapi import
|
| 7 |
from fastapi.security import APIKeyHeader
|
| 8 |
from openai import OpenAI
|
| 9 |
import openai
|
| 10 |
import pandas as pd
|
| 11 |
-
from pydantic import BaseModel
|
| 12 |
import os
|
| 13 |
import logging
|
| 14 |
import json
|
|
@@ -17,17 +16,11 @@ from psycopg2 import sql
|
|
| 17 |
import os
|
| 18 |
from dotenv import load_dotenv
|
| 19 |
from datetime import datetime, timezone
|
| 20 |
-
import threading
|
| 21 |
import pickle # Replace dill with pickle
|
| 22 |
-
from cachetools import TTLCache
|
| 23 |
-
import threading
|
| 24 |
-
import time
|
| 25 |
import uuid
|
| 26 |
from app.cache import CustomTTLCache, upload_file_to_s3
|
| 27 |
import pdfkit
|
| 28 |
import PyPDF2
|
| 29 |
-
import secrets
|
| 30 |
-
import string
|
| 31 |
|
| 32 |
from app.exceptions import BaseOurcoachException, DBError, OpenAIRequestError, UtilsError
|
| 33 |
|
|
@@ -346,7 +339,7 @@ def generate_html(json_data, coach_name='Growth Guide', booking_id = None):
|
|
| 346 |
raise DBError(user_id="no-user", message="Error uploading file to S3", code="S3Error")
|
| 347 |
|
| 348 |
@catch_error
|
| 349 |
-
def get_user_summary(user_id):
|
| 350 |
function_name = get_user_summary.__name__
|
| 351 |
logger.info(f"Generating user summary for user {user_id}", extra={'user_id': user_id, 'endpoint': function_name})
|
| 352 |
|
|
@@ -819,7 +812,8 @@ def get_user_summary(user_id):
|
|
| 819 |
# reports['html_report'] = html_output
|
| 820 |
|
| 821 |
# Store users_growth_guide_preparation_brief in the User object
|
| 822 |
-
|
|
|
|
| 823 |
|
| 824 |
# Step 4: Return the JSON reports
|
| 825 |
logger.info(f"User summary generated successfully for user {user_id}", extra={'user_id': user_id, 'endpoint': function_name})
|
|
@@ -1043,7 +1037,6 @@ def get_user_info(user_id):
|
|
| 1043 |
{user_data_clean.get('firstName', '')}'s challenges (You **must** use this information for the PLANNING STATE):
|
| 1044 |
{challenges}
|
| 1045 |
|
| 1046 |
-
{user_data_clean.get('firstName', '')}'s Legendary Persona: {user_data_clean.get('legendPersona', '')}
|
| 1047 |
Pronouns: {user_data_clean.get('pronouns', '')}
|
| 1048 |
Birthday: {user_data_clean.get('birthDate', '')}
|
| 1049 |
{user_data_clean.get('firstName', '')}'s MBTI: {user_data_clean.get('mbti', '')}
|
|
@@ -1062,7 +1055,7 @@ def get_user_info(user_id):
|
|
| 1062 |
{whoImportant}
|
| 1063 |
"""
|
| 1064 |
logger.info(f"User info retrieved successfully for {user_id}", extra={'user_id': user_id, 'endpoint': function_name})
|
| 1065 |
-
return user_data_formatted, user_data_clean.get('
|
| 1066 |
else:
|
| 1067 |
logger.warning(f"No user info found for {user_id}", extra={'user_id': user_id, 'endpoint': function_name})
|
| 1068 |
raise DBError(user_id=user_id, message="Error retrieving user info", code="NoOnboardingError", e=str(e))
|
|
@@ -1402,6 +1395,22 @@ def get_users_mementos(user_id, date):
|
|
| 1402 |
finally:
|
| 1403 |
return mementos
|
| 1404 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1405 |
@catch_error
|
| 1406 |
def get_user_subscriptions(user_id):
|
| 1407 |
function_name = get_user_subscriptions.__name__
|
|
|
|
| 1 |
import logging
|
| 2 |
import boto3
|
| 3 |
+
from botocore.exceptions import NoCredentialsError, PartialCredentialsError
|
| 4 |
import os
|
| 5 |
from dotenv import load_dotenv
|
| 6 |
+
from fastapi import HTTPException, Security, Query, status
|
| 7 |
from fastapi.security import APIKeyHeader
|
| 8 |
from openai import OpenAI
|
| 9 |
import openai
|
| 10 |
import pandas as pd
|
|
|
|
| 11 |
import os
|
| 12 |
import logging
|
| 13 |
import json
|
|
|
|
| 16 |
import os
|
| 17 |
from dotenv import load_dotenv
|
| 18 |
from datetime import datetime, timezone
|
|
|
|
| 19 |
import pickle # Replace dill with pickle
|
|
|
|
|
|
|
|
|
|
| 20 |
import uuid
|
| 21 |
from app.cache import CustomTTLCache, upload_file_to_s3
|
| 22 |
import pdfkit
|
| 23 |
import PyPDF2
|
|
|
|
|
|
|
| 24 |
|
| 25 |
from app.exceptions import BaseOurcoachException, DBError, OpenAIRequestError, UtilsError
|
| 26 |
|
|
|
|
| 339 |
raise DBError(user_id="no-user", message="Error uploading file to S3", code="S3Error")
|
| 340 |
|
| 341 |
@catch_error
|
| 342 |
+
def get_user_summary(user_id, update_rec_topics=False):
|
| 343 |
function_name = get_user_summary.__name__
|
| 344 |
logger.info(f"Generating user summary for user {user_id}", extra={'user_id': user_id, 'endpoint': function_name})
|
| 345 |
|
|
|
|
| 812 |
# reports['html_report'] = html_output
|
| 813 |
|
| 814 |
# Store users_growth_guide_preparation_brief in the User object
|
| 815 |
+
if update_rec_topics:
|
| 816 |
+
user.set_recommened_gg_topics(reports['users_growth_guide_preparation_brief'])
|
| 817 |
|
| 818 |
# Step 4: Return the JSON reports
|
| 819 |
logger.info(f"User summary generated successfully for user {user_id}", extra={'user_id': user_id, 'endpoint': function_name})
|
|
|
|
| 1037 |
{user_data_clean.get('firstName', '')}'s challenges (You **must** use this information for the PLANNING STATE):
|
| 1038 |
{challenges}
|
| 1039 |
|
|
|
|
| 1040 |
Pronouns: {user_data_clean.get('pronouns', '')}
|
| 1041 |
Birthday: {user_data_clean.get('birthDate', '')}
|
| 1042 |
{user_data_clean.get('firstName', '')}'s MBTI: {user_data_clean.get('mbti', '')}
|
|
|
|
| 1055 |
{whoImportant}
|
| 1056 |
"""
|
| 1057 |
logger.info(f"User info retrieved successfully for {user_id}", extra={'user_id': user_id, 'endpoint': function_name})
|
| 1058 |
+
return user_data_formatted, user_data_clean.get('legendPersona', '')
|
| 1059 |
else:
|
| 1060 |
logger.warning(f"No user info found for {user_id}", extra={'user_id': user_id, 'endpoint': function_name})
|
| 1061 |
raise DBError(user_id=user_id, message="Error retrieving user info", code="NoOnboardingError", e=str(e))
|
|
|
|
| 1395 |
finally:
|
| 1396 |
return mementos
|
| 1397 |
|
| 1398 |
+
@catch_error
|
| 1399 |
+
def id_to_persona(assistant_id):
|
| 1400 |
+
# persona_to_assistant = {
|
| 1401 |
+
# "Coach Steve": "asst_mUm6MBcW544p1iVov9mwIC96",
|
| 1402 |
+
# "Coach Aris": "asst_4WcktKgYdDnXA1QUlWvrNfWV",
|
| 1403 |
+
# "Coach Teresa": "asst_4UVkFK6r2pbz6NK6kNzG4sTW"
|
| 1404 |
+
# }
|
| 1405 |
+
|
| 1406 |
+
assistant_to_persona = {
|
| 1407 |
+
"asst_mUm6MBcW544p1iVov9mwIC96": "Coach Steve, based on the persona of Steve Jobs",
|
| 1408 |
+
"asst_4WcktKgYdDnXA1QUlWvrNfWV": "Coach Aris, based on the persona of Aristotle",
|
| 1409 |
+
"asst_4UVkFK6r2pbz6NK6kNzG4sTW": "Coach Teresa, based on the persona of Mother Teresa"
|
| 1410 |
+
}
|
| 1411 |
+
|
| 1412 |
+
return assistant_to_persona.get(assistant_id, "Coach Steve, based on the persona of Steve Jobs")
|
| 1413 |
+
|
| 1414 |
@catch_error
|
| 1415 |
def get_user_subscriptions(user_id):
|
| 1416 |
function_name = get_user_subscriptions.__name__
|