Upload 6 files
Browse files
agents.py
ADDED
@@ -0,0 +1,188 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import functools
|
2 |
+
from langchain.agents import AgentExecutor, create_openai_tools_agent
|
3 |
+
from langchain_core.messages import HumanMessage
|
4 |
+
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
|
5 |
+
from langchain_openai import ChatOpenAI
|
6 |
+
from langchain.output_parsers.openai_functions import JsonOutputFunctionsParser
|
7 |
+
import tools
|
8 |
+
from tools import tools
|
9 |
+
import os
|
10 |
+
import config
|
11 |
+
|
12 |
+
|
13 |
+
os.environ["OPENAI_API_KEY"] = config.config("OPENAI_API_KEY")
|
14 |
+
|
15 |
+
# initializing the GPT-4 Turbo model with no temperature variation
|
16 |
+
llm = ChatOpenAI(temperature=0, model="gpt-4-turbo-preview")
|
17 |
+
|
18 |
+
def create_agents(llm:ChatOpenAI, tools:list, system_prompt:str)->AgentExecutor:
|
19 |
+
# creating a chat prompt template
|
20 |
+
prompt = ChatPromptTemplate.from_messages([
|
21 |
+
('system', system_prompt),
|
22 |
+
MessagesPlaceholder(variable_name='messages'),
|
23 |
+
MessagesPlaceholder(variable_name="agent_scratchpad")
|
24 |
+
])
|
25 |
+
|
26 |
+
# creating an agent with specified tools and prompting template
|
27 |
+
agent = create_openai_tools_agent(llm, tools, prompt)
|
28 |
+
executor = AgentExecutor(agent=agent, tools=tools)
|
29 |
+
return executor
|
30 |
+
|
31 |
+
# function to handle the agent invocation and return formatted state
|
32 |
+
def agent_node(state, agent, name):
|
33 |
+
result = agent.invoke(state)
|
34 |
+
return {"messages": [HumanMessage(content=result["output"], name=name)]}
|
35 |
+
|
36 |
+
# list of agents representing different coaching roles
|
37 |
+
members = ["nutritionist", "workout_coach", "mental_health_coach","sleep_coach","hydration_coach",
|
38 |
+
"posture_and_ergonomics_coach","injury_prevention_and_recovery_coach"]
|
39 |
+
|
40 |
+
# system prompt explaining the FIT.AI role and its tasks
|
41 |
+
system_prompt = (
|
42 |
+
"""
|
43 |
+
TASK:
|
44 |
+
You are "FIT.AI", an intelligent chatbot that answers questions about fitness and overall health.
|
45 |
+
You also supervise and coordinate tasks among seven workers: {members}.
|
46 |
+
Based on the user's request, determine which worker should take the next action.
|
47 |
+
Each worker is responsible for executing specific tasks and reporting back their findings and progress.
|
48 |
+
|
49 |
+
Example session :
|
50 |
+
|
51 |
+
User question : Hello, help me with a fitness and diet plan.
|
52 |
+
Thought : I should first ask the user their daily routine and then
|
53 |
+
search the web for the most optimal fitness and diet plan first.
|
54 |
+
Action : Search the web for optimal results.
|
55 |
+
Pause : You will take some time to think
|
56 |
+
You then output : Please provide your daily routine so as to tailor the plan accordingly.
|
57 |
+
"""
|
58 |
+
)
|
59 |
+
|
60 |
+
# options for routing the next step in the flow
|
61 |
+
options = ['FINISH'] + members
|
62 |
+
|
63 |
+
# function definition for routing the tasks to agents
|
64 |
+
function_def = {
|
65 |
+
"name": "route",
|
66 |
+
"description": "Select the next role.",
|
67 |
+
"parameters": {
|
68 |
+
"title": "routeSchema",
|
69 |
+
"type": "object",
|
70 |
+
"properties": {"next": {"title": "Next", "anyOf": [{"enum": options}]}},
|
71 |
+
"required": ["next"]
|
72 |
+
}
|
73 |
+
}
|
74 |
+
|
75 |
+
# creating the supervisor chain using the specified LLM and function definitions
|
76 |
+
prompt = ChatPromptTemplate.from_messages(
|
77 |
+
[
|
78 |
+
("system", system_prompt),
|
79 |
+
MessagesPlaceholder(variable_name="messages"),
|
80 |
+
(
|
81 |
+
"system",
|
82 |
+
"Given the conversation above, who should act next?"
|
83 |
+
" Or should we FINISH? Select one of: {options}",
|
84 |
+
),
|
85 |
+
]).partial(options=str(options), members=", ".join(members))
|
86 |
+
|
87 |
+
supervisor_chain = (
|
88 |
+
prompt
|
89 |
+
| llm.bind_functions(functions=[function_def], function_call="route")
|
90 |
+
| JsonOutputFunctionsParser()
|
91 |
+
)
|
92 |
+
|
93 |
+
# creating agents for each coach role with specified prompts and tools
|
94 |
+
nutritionist_agent = create_agents(
|
95 |
+
llm,
|
96 |
+
tools,
|
97 |
+
"""Your role is to act as a knowledgeable nutritionist. Provide practical dietary
|
98 |
+
advice and create meal plans. Research the latest nutritional information and trends,
|
99 |
+
and give personalized recommendations based on the user's needs and country of choice.
|
100 |
+
Utilize information from the workout coach to suggest a diet plan. Always mention any web/mobile applications for tracking
|
101 |
+
calorie intake and identify potential food allergies. If no applications are found,
|
102 |
+
provide useful tips. Respond in a friendly, informal tone."""
|
103 |
+
)
|
104 |
+
|
105 |
+
workout_coach_agent = create_agents(
|
106 |
+
llm,
|
107 |
+
tools,
|
108 |
+
"""You are a workout coach. Based on the user's fitness goals and nutritionist's suggestions,
|
109 |
+
create tailored workout plans. Provide exercise routines, tips for proper form, and motivation.
|
110 |
+
Suggest home workout equipment along with online links to purchase them and useful fitness tracking applications or websites.
|
111 |
+
Respond in a friendly, informal tone, offering positive affirmations and practical
|
112 |
+
timelines for achieving goals."""
|
113 |
+
)
|
114 |
+
|
115 |
+
mental_health_coach_agent = create_agents(
|
116 |
+
llm,
|
117 |
+
tools,
|
118 |
+
"""You are a mental health coach. Provide support and mindfulness strategies to improve
|
119 |
+
mental well-being taking into account the user's dietary and workout plans. Research techniques
|
120 |
+
and practices to help with mental health and offer insights into mental health disorders if queried.
|
121 |
+
Reccommend home tips based in the user's activity level.
|
122 |
+
Suggest useful apps for maintaining mental stability. Respond in a friendly, informal tone."""
|
123 |
+
)
|
124 |
+
|
125 |
+
sleep_coach_agent = create_agents(
|
126 |
+
llm,
|
127 |
+
tools,
|
128 |
+
"""You are a sleep coach. Provide tips for better sleep hygiene, suggest tools and techniques
|
129 |
+
to improve sleep quality, and offer advice on optimizing sleep habits based on the
|
130 |
+
user's daily routine and age . Mention any web or mobile applications for tracking sleep
|
131 |
+
patterns and provide relaxation techniques. Respond in a friendly, informal tone."""
|
132 |
+
)
|
133 |
+
|
134 |
+
hydration_coach_agent = create_agents(
|
135 |
+
llm,
|
136 |
+
tools,
|
137 |
+
"""You are a hydration coach. Help users maintain proper hydration levels by providing advice on water intake
|
138 |
+
and the importance of staying hydrated. Suggest tools and techniques for tracking water consumption and offer
|
139 |
+
tips for improving hydration habits based on the user's daily routine. Also, gives hydration advice, complementing the meal and workout plans results provided
|
140 |
+
by the nutritionist and workout coach. Always ask users to drink water based on the gender.
|
141 |
+
Respond in a friendly, informal tone."""
|
142 |
+
)
|
143 |
+
|
144 |
+
posture_and_ergonomics_coach_agent = create_agents(
|
145 |
+
llm,
|
146 |
+
tools,
|
147 |
+
"""You are a posture and ergonomics coach. Provide guidance on maintaining good posture, especially for individuals
|
148 |
+
who spend long hours sitting, and recommend ergonomic adjustments depending on the workspace. Suggest tools and
|
149 |
+
techniques for tracking and improving posture. Respond in a friendly, informal tone."""
|
150 |
+
)
|
151 |
+
|
152 |
+
injury_prevention_and_recovery_coach_agent = create_agents(
|
153 |
+
llm,
|
154 |
+
tools,
|
155 |
+
"""You are an injury prevention and recovery coach. Help users prevent injuries by providing exercises
|
156 |
+
and tips for proper form and recovery strategies if an injury occurs. If user is injured provide quick and
|
157 |
+
relevant solutions for the particular injury. Always reccommend seeking a doctor.
|
158 |
+
Suggest tools and techniques for tracking and managing recovery. Respond in a friendly, informal tone."""
|
159 |
+
)
|
160 |
+
|
161 |
+
|
162 |
+
nutritionist_node = functools.partial(
|
163 |
+
agent_node, agent=nutritionist_agent, name="nutritionist"
|
164 |
+
)
|
165 |
+
|
166 |
+
workout_coach_node = functools.partial(
|
167 |
+
agent_node, agent=workout_coach_agent, name="workout_coach"
|
168 |
+
)
|
169 |
+
|
170 |
+
mental_health_coach_node = functools.partial(
|
171 |
+
agent_node, agent=mental_health_coach_agent, name="mental_health_coach"
|
172 |
+
)
|
173 |
+
|
174 |
+
sleep_coach_node = functools.partial(
|
175 |
+
agent_node, agent=sleep_coach_agent, name="sleep_coach"
|
176 |
+
)
|
177 |
+
|
178 |
+
hydration_coach_node = functools.partial(
|
179 |
+
agent_node, agent=hydration_coach_agent, name="hydration_coach"
|
180 |
+
)
|
181 |
+
|
182 |
+
posture_and_ergonomics_coach_node = functools.partial(
|
183 |
+
agent_node, agent=posture_and_ergonomics_coach_agent, name="posture_and_ergonomics_coach"
|
184 |
+
)
|
185 |
+
|
186 |
+
injury_prevention_and_recovery_coach_node = functools.partial(
|
187 |
+
agent_node, agent=injury_prevention_and_recovery_coach_agent, name="injury_prevention_and_recovery_coach"
|
188 |
+
)
|
app.py
ADDED
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import gradio as gr
|
2 |
+
from langchain_core.messages import HumanMessage
|
3 |
+
from config import *
|
4 |
+
from tools import tools
|
5 |
+
from agents import *
|
6 |
+
from workflow import create_workflow
|
7 |
+
|
8 |
+
graph = create_workflow()
|
9 |
+
|
10 |
+
def run_graph(input_message, history):
|
11 |
+
try:
|
12 |
+
# relevant fitness-related keywords to handle irrelevant user prompts
|
13 |
+
relevant_keywords = [
|
14 |
+
"workout", "training", "exercise", "cardio", "strength training", "hiit (high-intensity interval training)",
|
15 |
+
"flexibility", "yoga", "pilates", "aerobics", "crossfit", "bodybuilding", "endurance", "running",
|
16 |
+
"cycling", "swimming", "martial arts", "stretching", "warm-up", "cool-down",
|
17 |
+
"diet plan", "meal plan", "macronutrients", "micronutrients", "vitamins", "minerals", "protein",
|
18 |
+
"carbohydrates", "fats", "calories", "calorie", "daily", "nutrition", "supplements", "hydration", "weightloss",
|
19 |
+
"weight gain", "healthy eating","health", "fitness", "intermittent fasting", "keto diet", "vegan diet", "paleo diet",
|
20 |
+
"mediterranean diet", "gluten-free", "low-carb", "high-protein", "bmi", "calculate", "body mass index", 'calculator'
|
21 |
+
"mental health", "mindfulness", "meditation", "stress management", "anxiety relief", "depression",
|
22 |
+
"positive thinking", "motivation", "self-care", "relaxation", "sleep hygiene", "therapy",
|
23 |
+
"counseling", "cognitive-behavioral therapy (cbt)", "mood tracking", "mental", "emotional well-being",
|
24 |
+
"healthy lifestyle", "fitness goals", "health routines", "daily habits", "ergonomics",
|
25 |
+
"posture", "work-life balance", "workplace", "habit tracking", "goal setting", "personal growth",
|
26 |
+
"injury prevention", "recovery", "rehabilitation", "physical therapy", "sports injuries",
|
27 |
+
"pain management", "recovery techniques", "foam rolling", "stretching exercises",
|
28 |
+
"injury management", "injuries", "apps", "health tracking", "wearable technology", "equipment",
|
29 |
+
"home workouts", "gym routines", "outdoor activities", "sports", "wellness tips", "water", "adult", "adults"
|
30 |
+
"child", "children", "infant", "sleep", "habit", "habits", "routine", "loose", "weight", "fruits", "vegetables",
|
31 |
+
"chicken", "veg", "vegetarian", "non-veg", "non-vegetarian", "plant", "plant-based", "plant based", "fat", "resources",
|
32 |
+
"help", "cutting", "bulking", "link", "links", "website", "online", "websites", "peace", "mind", "equipments", "equipment",
|
33 |
+
"watch", "tracker", "watch", "band", "height", "injured", "quick", "remedy", "solution", "solutions", "pain", "male", "female"
|
34 |
+
]
|
35 |
+
|
36 |
+
greetings=["hello", "hi", "how are you doing"]
|
37 |
+
|
38 |
+
# Check if the input message contains any relevant keywords
|
39 |
+
if any(keyword in input_message.lower() for keyword in relevant_keywords):
|
40 |
+
response = graph.invoke({
|
41 |
+
"messages": [HumanMessage(content=input_message)]
|
42 |
+
})
|
43 |
+
return response['messages'][1].content
|
44 |
+
|
45 |
+
elif any(keyword in input_message.lower() for keyword in greetings):
|
46 |
+
return "Hi there, I am FIT bot, your personal wellbeing coach "
|
47 |
+
|
48 |
+
else:
|
49 |
+
return "I'm here to assist with fitness, nutrition, mental health, and related topics. Please ask questions related to these areas."
|
50 |
+
except Exception as e:
|
51 |
+
return f"An error occurred while processing your request: {e}"
|
52 |
+
|
53 |
+
|
54 |
+
|
55 |
+
bot = gr.Chatbot(render=False,placeholder="<strong>Your Personal Assistant</strong><br>Ask Me Anything",
|
56 |
+
show_copy_button=True,
|
57 |
+
layout="bubble",
|
58 |
+
container=True,
|
59 |
+
label="FIT.AI",
|
60 |
+
show_label=True,
|
61 |
+
avatar_images=("user.png","bot.png"),
|
62 |
+
likeable=True)
|
63 |
+
|
64 |
+
|
65 |
+
demo = gr.ChatInterface(
|
66 |
+
fn=run_graph,
|
67 |
+
clear_btn="๐๏ธ Clear",
|
68 |
+
theme="soft",
|
69 |
+
undo_btn="Delete Previous",
|
70 |
+
autofocus=True,
|
71 |
+
textbox=gr.Textbox(placeholder="Ask away any fitness related questions", scale=7),
|
72 |
+
stop_btn="Stop",
|
73 |
+
show_progress="full",
|
74 |
+
description="<strong>An intelligent assistant for fitness, diet and mental health guidance.<strong>",
|
75 |
+
js="custom.js",
|
76 |
+
examples=["Provide health and fitness tips", "My daily Calorie intake",
|
77 |
+
"Better mental health","Best sleep habits","Water intake for a fully grown adult",
|
78 |
+
"Ergonomics in the workplace","Injuries Rehabilitation"],
|
79 |
+
chatbot=bot,
|
80 |
+
)
|
81 |
+
|
82 |
+
demo.launch(share=True)
|
config.py
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
from decouple import config
|
3 |
+
|
4 |
+
# Set environment variables
|
5 |
+
os.environ["OPENAI_API_KEY"] = config("OPENAI_API_KEY")
|
6 |
+
os.environ["TAVILY_API_KEY"] = config("TAVILY_API_KEY")
|
tools.py
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import requests
|
2 |
+
from bs4 import BeautifulSoup
|
3 |
+
from langchain.tools import tool
|
4 |
+
from tavily import TavilyClient
|
5 |
+
import os
|
6 |
+
|
7 |
+
tavily_client = TavilyClient(api_key=os.getenv("TAVILY_API_KEY"))
|
8 |
+
|
9 |
+
# tool for processing web content
|
10 |
+
@tool("process_search_tool", return_direct=False)
|
11 |
+
def process_search_tool(url: str) -> str:
|
12 |
+
"""Used to process content found on the internet."""
|
13 |
+
try:
|
14 |
+
response = requests.get(url=url)
|
15 |
+
soup = BeautifulSoup(response.content, "html.parser")
|
16 |
+
return soup.get_text()
|
17 |
+
except requests.exceptions.RequestException as e:
|
18 |
+
return f"Error processing the URL: {str(e)}"
|
19 |
+
|
20 |
+
# tool for internet searches
|
21 |
+
@tool("internet_search_tool", return_direct=False)
|
22 |
+
def internet_search_tool(query: str) -> str:
|
23 |
+
"""Search user query on the internet using TavilyAPI."""
|
24 |
+
try:
|
25 |
+
response = tavily_client.qna_search(query=query, max_results=5)
|
26 |
+
return response if response else "No results found"
|
27 |
+
except requests.exceptions.HTTPError as e:
|
28 |
+
return f"HTTP Error: {str(e)}"
|
29 |
+
|
30 |
+
tools = [internet_search_tool, process_search_tool]
|
user.png
ADDED
![]() |
workflow.py
ADDED
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import operator
|
2 |
+
from langchain_core.messages import BaseMessage
|
3 |
+
from langgraph.graph import StateGraph, END, START
|
4 |
+
from typing import TypedDict, Annotated, Sequence
|
5 |
+
from agents import supervisor_chain,nutritionist_node,workout_coach_node,mental_health_coach_node,members,sleep_coach_node,hydration_coach_node,posture_and_ergonomics_coach_node,injury_prevention_and_recovery_coach_node
|
6 |
+
|
7 |
+
|
8 |
+
# define the state structure for agents
|
9 |
+
class AgentState(TypedDict):
|
10 |
+
messages: Annotated[Sequence[BaseMessage], operator.add]
|
11 |
+
next: str
|
12 |
+
|
13 |
+
# function to create the workflow graph
|
14 |
+
def create_workflow():
|
15 |
+
workflow = StateGraph(AgentState)
|
16 |
+
workflow.add_node("supervisor", action=supervisor_chain) # addign nodes to the graph
|
17 |
+
workflow.add_node("nutritionist", action=nutritionist_node)
|
18 |
+
workflow.add_node("workout_coach", action=workout_coach_node)
|
19 |
+
workflow.add_node("mental_health_coach", action=mental_health_coach_node)
|
20 |
+
workflow.add_node("sleep_coach", action=sleep_coach_node)
|
21 |
+
workflow.add_node("hydration_coach", action=hydration_coach_node)
|
22 |
+
workflow.add_node("posture_and_ergonomics_coach", action=posture_and_ergonomics_coach_node)
|
23 |
+
workflow.add_node("injury_prevention_and_recovery_coach", action=injury_prevention_and_recovery_coach_node)
|
24 |
+
|
25 |
+
for member in members:
|
26 |
+
workflow.add_edge(start_key=member, end_key="supervisor")
|
27 |
+
|
28 |
+
conditional_map = {k: k for k in members}
|
29 |
+
conditional_map["FINISH"] = END
|
30 |
+
|
31 |
+
|
32 |
+
workflow.add_conditional_edges("supervisor", lambda x: x["next"], conditional_map)
|
33 |
+
workflow.add_edge(START, "supervisor")
|
34 |
+
|
35 |
+
graph= workflow.compile()
|
36 |
+
|
37 |
+
return graph
|