mgbam commited on
Commit
a367b14
·
verified ·
1 Parent(s): 49078fd

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +41 -134
app.py CHANGED
@@ -2,33 +2,11 @@ import gradio as gr
2
  import numpy as np
3
  import sqlite3
4
  import json
5
- import time
6
  from PIL import Image, ImageDraw
7
 
8
- # ------ Mock MCP Server Implementation ------
9
- class MockMCPServer:
10
- def __init__(self):
11
- self.tools = {}
12
-
13
- def register_tool(self, name, func, description):
14
- self.tools[name] = {
15
- "function": func,
16
- "description": description
17
- }
18
-
19
- def call_tool(self, tool_name, params):
20
- if tool_name in self.tools:
21
- return self.tools[tool_name]["function"](**params)
22
- return {"error": f"Tool {tool_name} not found"}
23
-
24
- # ------ Create Mock MCP Server ------
25
- mcp_server = MockMCPServer()
26
-
27
  # ------ Tool Implementations ------
28
  def get_recipe_by_ingredients(ingredients):
29
  """Find recipes based on available ingredients"""
30
- # In a real implementation, this would call an API
31
- print(f"Searching recipes with ingredients: {ingredients}")
32
  return {
33
  "recipes": [
34
  {"name": "Vegetable Stir Fry", "time": 20, "difficulty": "Easy"},
@@ -38,8 +16,7 @@ def get_recipe_by_ingredients(ingredients):
38
 
39
  def get_recipe_image(recipe_name):
40
  """Generate an image of the finished recipe"""
41
- print(f"Generating image for: {recipe_name}")
42
- # Create a placeholder image with the recipe name
43
  img = Image.new('RGB', (300, 200), color=(73, 109, 137))
44
  d = ImageDraw.Draw(img)
45
  d.text((10,10), f"Image of: {recipe_name}", fill=(255,255,0))
@@ -47,7 +24,6 @@ def get_recipe_image(recipe_name):
47
 
48
  def convert_measurements(amount, from_unit, to_unit):
49
  """Convert cooking measurements between units"""
50
- print(f"Converting {amount} {from_unit} to {to_unit}")
51
  conversions = {
52
  ("tbsp", "tsp"): lambda x: x * 3,
53
  ("cups", "ml"): lambda x: x * 240,
@@ -79,55 +55,27 @@ def init_recipe_db():
79
  conn.commit()
80
  return conn
81
 
82
- # ------ Voice Processing Functions ------
83
- def text_to_speech(text):
84
- """Mock TTS function - in real use, replace with actual TTS"""
85
- print(f"[TTS]: {text}")
86
- # Return dummy audio data (silence)
87
- duration = 2 # seconds
88
- sample_rate = 44100
89
- samples = np.zeros(int(duration * sample_rate), dtype=np.float32)
90
- return (sample_rate, samples)
91
-
92
- def speech_to_text(audio):
93
- """Mock STT function - in real use, replace with actual STT"""
94
- # For now, we return a fixed string. In reality, we would process the audio
95
- sample_rate, audio_data = audio
96
- print(f"Received audio with sample rate {sample_rate} and shape {audio_data.shape}")
97
- # Return a fixed response for demo
98
- return "What can I make with eggs and flour?"
99
-
100
  # ------ Agent Logic ------
101
  def process_query(query, db_conn):
102
- """Process user query using the available tools"""
103
  print(f"Processing query: {query}")
 
104
  # Simple intent recognition
105
  if "recipe" in query.lower() or "make" in query.lower() or "cook" in query.lower():
106
- # Extract ingredients - very simple, just use some keywords
107
- ingredients = []
108
- for word in ["eggs", "flour", "milk", "tomatoes", "onion", "garlic"]:
109
- if word in query.lower():
110
- ingredients.append(word)
111
- if not ingredients:
112
- ingredients = ["eggs", "flour"] # default
113
  return {
114
  "type": "recipes",
115
- "data": mcp_server.call_tool("get_recipe_by_ingredients", {"ingredients": ingredients})
116
  }
117
- elif "image" in query.lower() or "show" in query.lower() or "look" in query.lower():
118
- # Extract recipe name
119
- recipe_name = "Classic Pancakes" # default
120
- for recipe in ["pancakes", "stir fry", "tomato soup", "chocolate cake"]:
121
- if recipe in query.lower():
122
- recipe_name = recipe
123
- break
124
  return {
125
  "type": "image",
126
- "data": mcp_server.call_tool("get_recipe_image", {"recipe_name": recipe_name})
127
  }
128
  elif "convert" in query.lower():
129
- # Extract amount and units - very simple
130
- # Assume pattern: convert <number> <unit> to <unit>
131
  words = query.split()
132
  try:
133
  amount = float(words[words.index("convert")+1])
@@ -139,48 +87,32 @@ def process_query(query, db_conn):
139
  to_unit = "ml"
140
  return {
141
  "type": "conversion",
142
- "data": mcp_server.call_tool("convert_measurements", {"amount": amount, "from_unit": from_unit, "to_unit": to_unit})
143
  }
144
  else:
145
- # Fallback to database search
146
  c = db_conn.cursor()
147
  c.execute("SELECT * FROM recipes WHERE name LIKE ?", (f"%{query}%",))
148
- recipes = c.fetchall()
149
  return {
150
  "type": "db_recipes",
151
- "data": recipes
152
  }
153
 
154
- # ------ Register Tools with MCP Server ------
155
- mcp_server.register_tool(
156
- "get_recipe_by_ingredients",
157
- get_recipe_by_ingredients,
158
- "Find recipes based on available ingredients"
159
- )
160
- mcp_server.register_tool(
161
- "get_recipe_image",
162
- get_recipe_image,
163
- "Generate an image of the finished recipe"
164
- )
165
- mcp_server.register_tool(
166
- "convert_measurements",
167
- convert_measurements,
168
- "Convert cooking measurements between units"
169
- )
170
-
171
- # ------ Initialize System ------
172
- db_conn = init_recipe_db()
173
-
174
  # ------ Gradio Interface ------
175
  def process_voice_command(audio):
176
- """Process voice command through the agent system"""
177
- # Convert audio to text
178
- query = speech_to_text(audio)
 
 
 
 
 
 
179
 
180
- # Process query using agent logic
181
- result = process_query(query, db_conn)
182
 
183
- # Generate response text and image
184
  response_text = ""
185
  image = None
186
 
@@ -188,64 +120,39 @@ def process_voice_command(audio):
188
  recipes = result["data"]["recipes"]
189
  response_text = f"Found {len(recipes)} recipes:\n"
190
  for recipe in recipes:
191
- response_text += f"- {recipe['name']} ({recipe['time']} mins, {recipe['difficulty']})\n"
192
  elif result["type"] == "image":
193
- image = result["data"] # This is a PIL image
194
- response_text = "Here is an image of the recipe!"
195
  elif result["type"] == "conversion":
196
  conv = result["data"]
197
- if "error" in conv:
198
- response_text = f"Error: {conv['error']}"
199
- else:
200
- response_text = f"{conv['result']} {conv['unit']}"
201
  elif result["type"] == "db_recipes":
202
  recipes = result["data"]
203
- if recipes:
204
- response_text = f"Found {len(recipes)} recipes in database:\n"
205
- for recipe in recipes:
206
- response_text += f"- {recipe[1]} ({recipe[4]} mins)\n"
207
- else:
208
- response_text = "No recipes found."
209
- else:
210
- response_text = "I'm not sure how to help with that."
211
-
212
- # Convert response to audio
213
- sr, audio_data = text_to_speech(response_text)
214
 
215
- # Return results: audio output, text, and image
216
- return (sr, audio_data), response_text, image
217
 
218
- # ------ Hugging Face Space UI ------
219
- with gr.Blocks(title="MCP Culinary Voice Assistant") as demo:
220
  gr.Markdown("# 🧑‍🍳 MCP-Powered Culinary Voice Assistant")
221
- gr.Markdown("Speak to your cooking assistant about recipes, conversions, and more!")
222
 
223
  with gr.Row():
 
224
  with gr.Column():
225
- audio_input = gr.Audio(source="microphone", type="numpy", label="Speak to Chef Assistant")
226
- submit_btn = gr.Button("Process Command", variant="primary")
227
- with gr.Column():
228
- audio_output = gr.Audio(label="Assistant Response", interactive=False)
229
 
230
- with gr.Row():
231
- text_output = gr.Textbox(label="Transcription", interactive=False)
232
- image_output = gr.Image(label="Recipe Image", interactive=False)
233
 
234
  submit_btn.click(
235
  fn=process_voice_command,
236
  inputs=[audio_input],
237
- outputs=[audio_output, text_output, image_output]
238
- )
239
-
240
- gr.Examples(
241
- examples=[
242
- ["What can I make with eggs and flour?"],
243
- ["Show me how tomato soup looks"],
244
- ["Convert 2 cups to milliliters"],
245
- ["Find chocolate cake recipes"]
246
- ],
247
- inputs=[text_output],
248
- label="Example Queries"
249
  )
250
 
251
  if __name__ == "__main__":
 
2
  import numpy as np
3
  import sqlite3
4
  import json
 
5
  from PIL import Image, ImageDraw
6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  # ------ Tool Implementations ------
8
  def get_recipe_by_ingredients(ingredients):
9
  """Find recipes based on available ingredients"""
 
 
10
  return {
11
  "recipes": [
12
  {"name": "Vegetable Stir Fry", "time": 20, "difficulty": "Easy"},
 
16
 
17
  def get_recipe_image(recipe_name):
18
  """Generate an image of the finished recipe"""
19
+ # Create placeholder image
 
20
  img = Image.new('RGB', (300, 200), color=(73, 109, 137))
21
  d = ImageDraw.Draw(img)
22
  d.text((10,10), f"Image of: {recipe_name}", fill=(255,255,0))
 
24
 
25
  def convert_measurements(amount, from_unit, to_unit):
26
  """Convert cooking measurements between units"""
 
27
  conversions = {
28
  ("tbsp", "tsp"): lambda x: x * 3,
29
  ("cups", "ml"): lambda x: x * 240,
 
55
  conn.commit()
56
  return conn
57
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  # ------ Agent Logic ------
59
  def process_query(query, db_conn):
60
+ """Process user query"""
61
  print(f"Processing query: {query}")
62
+
63
  # Simple intent recognition
64
  if "recipe" in query.lower() or "make" in query.lower() or "cook" in query.lower():
65
+ ingredients = [word for word in ["eggs", "flour", "milk", "tomatoes"] if word in query.lower()]
66
+ if not ingredients:
67
+ ingredients = ["eggs", "flour"]
 
 
 
 
68
  return {
69
  "type": "recipes",
70
+ "data": get_recipe_by_ingredients(ingredients)
71
  }
72
+ elif "image" in query.lower() or "show" in query.lower():
73
+ recipe_name = next((r for r in ["pancakes", "soup", "cake"] if r in query.lower()), "pancakes")
 
 
 
 
 
74
  return {
75
  "type": "image",
76
+ "data": get_recipe_image(recipe_name)
77
  }
78
  elif "convert" in query.lower():
 
 
79
  words = query.split()
80
  try:
81
  amount = float(words[words.index("convert")+1])
 
87
  to_unit = "ml"
88
  return {
89
  "type": "conversion",
90
+ "data": convert_measurements(amount, from_unit, to_unit)
91
  }
92
  else:
 
93
  c = db_conn.cursor()
94
  c.execute("SELECT * FROM recipes WHERE name LIKE ?", (f"%{query}%",))
 
95
  return {
96
  "type": "db_recipes",
97
+ "data": c.fetchall()
98
  }
99
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
  # ------ Gradio Interface ------
101
  def process_voice_command(audio):
102
+ """Process voice command"""
103
+ # For demo purposes, we'll use text input directly
104
+ # In a real implementation, this would convert audio to text
105
+ sample_rate, audio_data = audio
106
+ query = "What can I make with eggs and flour?" # Fixed for demo
107
+
108
+ # Initialize database on first run
109
+ if not hasattr(process_voice_command, "db_conn"):
110
+ process_voice_command.db_conn = init_recipe_db()
111
 
112
+ # Process query
113
+ result = process_query(query, process_voice_command.db_conn)
114
 
115
+ # Generate response
116
  response_text = ""
117
  image = None
118
 
 
120
  recipes = result["data"]["recipes"]
121
  response_text = f"Found {len(recipes)} recipes:\n"
122
  for recipe in recipes:
123
+ response_text += f"- {recipe['name']} ({recipe['time']} mins)\n"
124
  elif result["type"] == "image":
125
+ image = result["data"]
126
+ response_text = "Here's an image of the recipe!"
127
  elif result["type"] == "conversion":
128
  conv = result["data"]
129
+ response_text = f"Result: {conv.get('result', '?')} {conv.get('unit', '')}" + \
130
+ (f"\nError: {conv['error']}" if "error" in conv else "")
 
 
131
  elif result["type"] == "db_recipes":
132
  recipes = result["data"]
133
+ response_text = f"Found {len(recipes)} recipes:\n" if recipes else "No recipes found."
134
+ for recipe in recipes:
135
+ response_text += f"- {recipe[1]} ({recipe[4]} mins)\n"
 
 
 
 
 
 
 
 
136
 
137
+ # Return results (no audio in this simplified version)
138
+ return None, response_text, image
139
 
140
+ # ------ Create Gradio Interface ------
141
+ with gr.Blocks(title="Culinary Voice Assistant") as demo:
142
  gr.Markdown("# 🧑‍🍳 MCP-Powered Culinary Voice Assistant")
 
143
 
144
  with gr.Row():
145
+ audio_input = gr.Audio(source="microphone", type="numpy", label="Speak to Chef")
146
  with gr.Column():
147
+ text_output = gr.Textbox(label="Assistant Response", interactive=False)
148
+ image_output = gr.Image(label="Recipe Image", interactive=False)
 
 
149
 
150
+ submit_btn = gr.Button("Process Command", variant="primary")
 
 
151
 
152
  submit_btn.click(
153
  fn=process_voice_command,
154
  inputs=[audio_input],
155
+ outputs=[gr.Audio(visible=False), text_output, image_output]
 
 
 
 
 
 
 
 
 
 
 
156
  )
157
 
158
  if __name__ == "__main__":