iDrops commited on
Commit
86004e5
·
verified ·
1 Parent(s): 91e76cf

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +202 -0
app.py ADDED
@@ -0,0 +1,202 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import re
3
+ from langgraph.checkpoint.sqlite import SqliteSaver
4
+ from langgraph.graph import StateGraph, END
5
+ from langchain_core.messages import SystemMessage, HumanMessage
6
+ from langchain_core.pydantic_v1 import BaseModel
7
+ from tavily import TavilyClient
8
+ from typing import TypedDict, List
9
+ from langchain_google_genai import ChatGoogleGenerativeAI
10
+ from dotenv import load_dotenv
11
+ import sys
12
+ import io
13
+ import gradio as gr
14
+
15
+ load_dotenv()
16
+
17
+ memory = SqliteSaver.from_conn_string(":memory:")
18
+
19
+ class AgentState(TypedDict):
20
+ task: str
21
+ plan: str
22
+ draft: str
23
+ critique: str
24
+ content: List[str]
25
+ revision_number: int
26
+ max_revisions: int
27
+
28
+ model = ChatGoogleGenerativeAI(model="gemini-1.5-pro", temperature=0.4)
29
+
30
+ PLAN_PROMPT = """You are an expert meal outline planner tasked with creating a meal plan outline.
31
+ Give the outline of the meal plan along with any relevant notes, calories,
32
+ recipes based on user preferences, shopping list based on ingredients, available ingredients or instructions for the recipe."""
33
+
34
+ WRITER_PROMPT = """You are an excellent meal planner generator tasked with writing excellent meal plans with schedules.
35
+ Write a detailed and concise final meal plan Following this template:
36
+ Breakfast -
37
+ Lunch -
38
+ Dinner -
39
+ Add optional snacks in between these times.
40
+ Please include the shopping list, calories, protein, and ingredients for the meal plan.
41
+ Generate the best meal plan possible for the user's request based on the provided template,
42
+ Provide every detail concisely.
43
+ If the user provides critique, respond with a revised version of your previous attempts.
44
+ Use all the information below as needed:
45
+ ------
46
+ {content}"""
47
+
48
+ REFLECTION_PROMPT = """You are a critic reviewing a meal plan.
49
+ Generate critique and recommendations for the user's meal plan.
50
+ Select the best recipes considering nutritional requirements and dietary restrictions.
51
+ Filter the recipes to ensure they meet the user's nutritional requirements and dietary restrictions considering calories and protein."""
52
+
53
+ RESEARCH_PLAN_PROMPT = """You are a researcher tasked with providing information to be used in writing a detailed meal plan according to the user meal plan outline.
54
+ Generate a list of search queries to gather relevant information regarding calories, protein, ingredients, and recipes. Generate a maximum of 3 queries."""
55
+
56
+ RESEARCH_CRITIQUE_PROMPT = """You are a researcher charged with providing information that can
57
+ be used when making any requested revisions. Generate a list of search queries to gather relevant information. Generate a maximum of 3 queries."""
58
+
59
+ class Queries(BaseModel):
60
+ queries: List[str]
61
+
62
+ tavily = TavilyClient(api_key=os.environ["TAVILY_API_KEY"])
63
+
64
+
65
+ def plan_node(state: AgentState):
66
+ messages = [
67
+ SystemMessage(content=PLAN_PROMPT),
68
+ HumanMessage(content=state['task'])
69
+ ]
70
+ response = model.invoke(messages)
71
+ plan_node_result = print("Plan agent Response: ", response.content)
72
+ plan_node_result
73
+ return {"plan": response.content}
74
+
75
+ def parse_queries(response_content):
76
+ # Extract queries from the response content using regex
77
+ pattern = r'\*\*"(.*?)"\*\*'
78
+ queries = re.findall(pattern, response_content)
79
+ return queries
80
+
81
+ def research_meal_plan_node(state: AgentState):
82
+ messages = [
83
+ SystemMessage(content=RESEARCH_PLAN_PROMPT),
84
+ HumanMessage(content=state['task'])
85
+ ]
86
+ response = model.invoke(messages)
87
+ queries = parse_queries(response.content)
88
+ content = state['content'] or []
89
+ for q in queries:
90
+ search_response = tavily.search(query=q, max_results=2)
91
+ for r in search_response['results']:
92
+ content.append(r['content'])
93
+ research_meal_plan_node = print("Research Meal Plan Response:", response.content) # Debug print
94
+ research_meal_plan_node
95
+ return {"content": content}
96
+
97
+ def generation_node(state: AgentState):
98
+ content = "\n\n".join(state['content'] or [])
99
+ user_message = HumanMessage(
100
+ content=f"{state['task']}\n\nHere is my meal plan:\n\n{state['plan']}")
101
+ messages = [
102
+ SystemMessage(
103
+ content=WRITER_PROMPT.format(content=content)
104
+ ),
105
+ user_message
106
+ ]
107
+ response = model.invoke(messages)
108
+ generation_node = print("Generation Response: ", response.content)
109
+ generation_node
110
+ return {
111
+ "draft": response.content,
112
+ "revision_number": state.get("revision_number", 1) + 1
113
+ }
114
+
115
+ def reflection_node(state: AgentState):
116
+ messages = [
117
+ SystemMessage(content=REFLECTION_PROMPT),
118
+ HumanMessage(content=state['draft'])
119
+ ]
120
+ response = model.invoke(messages)
121
+ reflection_node = print("Reflection Response:", response.content)
122
+ reflection_node
123
+ return {"critique": response.content}
124
+
125
+ def research_critique_node(state: AgentState):
126
+ messages = [
127
+ SystemMessage(content=RESEARCH_CRITIQUE_PROMPT),
128
+ HumanMessage(content=state['critique'])
129
+ ]
130
+ response = model.invoke(messages)
131
+ research_critique_node = print("Research Critique Response:", response.content) # Debug print
132
+ research_critique_node
133
+ queries = parse_queries(response.content)
134
+ content = state['content'] or []
135
+ for q in queries:
136
+ search_response = tavily.search(query=q, max_results=2)
137
+ for r in search_response['results']:
138
+ content.append(r['content'])
139
+ return {"content": content}
140
+
141
+ def should_continue(state):
142
+ if state["revision_number"] > state["max_revisions"]:
143
+ return END
144
+ return "reflect_plan"
145
+
146
+ builder = StateGraph(AgentState)
147
+
148
+ builder.add_node("meal_planner", plan_node)
149
+ builder.add_node("generate", generation_node)
150
+ builder.add_node("reflect_plan", reflection_node)
151
+ builder.add_node("research_meal_plan", research_meal_plan_node)
152
+ builder.add_node("research_critique", research_critique_node)
153
+
154
+ builder.set_entry_point("meal_planner")
155
+
156
+ builder.add_conditional_edges(
157
+ "generate",
158
+ should_continue,
159
+ {END: END, "reflect_plan": "reflect_plan"}
160
+ )
161
+
162
+ builder.add_edge("meal_planner", "research_meal_plan")
163
+ builder.add_edge("research_meal_plan", "generate")
164
+ builder.add_edge("reflect_plan", "research_critique")
165
+ builder.add_edge("research_critique", "generate")
166
+
167
+ graph = builder.compile(checkpointer=memory)
168
+
169
+ def start_agents(task, max_revisions):
170
+ # Save the current stdout
171
+ old_stdout = sys.stdout
172
+ sys.stdout = io.StringIO() # Redirect stdout to a buffer
173
+
174
+ try:
175
+ thread = {"configurable": {"thread_id": "1"}}
176
+ responses = list(graph.stream({
177
+ 'task': task,
178
+ "max_revisions": max_revisions,
179
+ "revision_number": 1
180
+ }, thread))
181
+ finally:
182
+ # Restore the original stdout
183
+ sys.stdout = old_stdout
184
+
185
+ if responses:
186
+ draft = responses[-1].get('generate', {}).get('draft', 'No draft found')
187
+ return draft
188
+ else:
189
+ return "No responses received"
190
+
191
+ interface = gr.Interface(
192
+ fn = start_agents,
193
+ inputs= [
194
+ gr.Textbox(lines=2, placeholder="Enter your meal planning task..."),
195
+ gr.Slider(1, 3, step=1, label="Max Revisions")
196
+ ],
197
+ outputs="text",
198
+ title="AI Meal Planner",
199
+ description="Generate meal plans based on your dietary requirements and preferences."
200
+ )
201
+
202
+ interface.launch()