nagasurendra commited on
Commit
ace7441
·
verified ·
1 Parent(s): 93f0ec0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +75 -66
app.py CHANGED
@@ -4,7 +4,6 @@ from tempfile import NamedTemporaryFile
4
  import os
5
  import ffmpeg
6
  from fuzzywuzzy import process, fuzz
7
- import phonetics
8
  from metaphone import doublemetaphone
9
  import logging
10
 
@@ -12,8 +11,9 @@ app = Flask(__name__)
12
  logging.basicConfig(level=logging.INFO)
13
 
14
  # Global variables
15
- cart = {}
16
- menu_preferences = "all"
 
17
  prices = {
18
  "samosa": 9,
19
  "onion pakoda": 10,
@@ -21,18 +21,18 @@ prices = {
21
  "chicken biryani": 14,
22
  "mutton biryani": 16,
23
  "veg biryani": 12,
24
- "panner butter": 10,
25
  "fish curry": 12,
26
  "chicken manchurian": 14,
27
  "veg manchurian": 12,
28
  "chilli chicken": 14,
29
- "panner biryani": 13,
30
  "chicken curry": 14
31
  }
32
  menus = {
33
  "all": list(prices.keys()),
34
  "vegetarian": [
35
- "samosa", "onion pakoda", "chilli gobi", "veg biryani", "panner butter", "veg manchurian", "panner biryani"
36
  ],
37
  "non-vegetarian": [
38
  "chicken biryani", "mutton biryani", "fish curry", "chicken manchurian", "chilli chicken", "chicken curry"
@@ -48,56 +48,46 @@ def index():
48
  def reset_cart():
49
  global cart, menu_preferences
50
  cart = {}
51
- menu_preferences = "all"
52
  return "Cart reset successfully."
53
 
54
  @app.route("/process-audio", methods=["POST"])
55
  def process_audio():
56
  try:
 
57
  audio_file = request.files.get("audio")
58
  if not audio_file:
59
  return jsonify({"response": "No audio file provided."}), 400
60
 
 
61
  temp_file = NamedTemporaryFile(delete=False, suffix=".webm")
62
  audio_file.save(temp_file.name)
63
 
64
  converted_file = NamedTemporaryFile(delete=False, suffix=".wav")
65
  ffmpeg.input(temp_file.name).output(
66
- converted_file.name, acodec="pcm_s16le", ac=1, ar="16000", af="highpass=f=200,lowpass=f=3000,acompressor"
67
  ).run(overwrite_output=True)
68
 
 
69
  recognizer = sr.Recognizer()
70
  recognizer.dynamic_energy_threshold = True
71
  recognizer.energy_threshold = 100
72
- recognizer.pause_threshold = 1.0
73
- recognizer.phrase_threshold = 0.3
74
- recognizer.non_speaking_duration = 0.2
75
-
76
  with sr.AudioFile(converted_file.name) as source:
77
  recognizer.adjust_for_ambient_noise(source, duration=1)
78
  audio_data = recognizer.record(source)
79
 
80
- raw_command = None
81
- for _ in range(2): # Retry recognition twice if needed
82
- try:
83
- raw_command = recognizer.recognize_google(audio_data).lower()
84
- break
85
- except sr.UnknownValueError:
86
- response = "Sorry, I couldn't catch that. Could you repeat?"
87
- logging.info(response)
88
-
89
- if raw_command is None:
90
- return jsonify({"response": "Sorry, I couldn't understand. Please try again."})
91
-
92
  logging.info(f"Raw recognized command: {raw_command}")
93
 
94
- # Preprocess command
95
  all_menu_items = menus["all"]
96
  command = preprocess_command(raw_command, all_menu_items)
97
 
98
- # Pass preprocessed command to process_command
99
  response = process_command(command)
100
 
 
 
101
  except Exception as e:
102
  response = f"An error occurred: {str(e)}"
103
  finally:
@@ -108,9 +98,9 @@ def process_audio():
108
 
109
  def preprocess_command(command, menu_items):
110
  """
111
- Preprocess the user command:
112
- - Normalize speech for accents and speed using fuzzy matching.
113
- - Phonetically match menu items.
114
  """
115
  def phonetic_match(word, options):
116
  word_phonetic = doublemetaphone(word)[0]
@@ -132,79 +122,97 @@ def preprocess_command(command, menu_items):
132
  return match
133
 
134
  return command
 
135
  def process_command(command):
 
 
 
136
  global cart, menu_preferences
137
  command = command.lower()
138
 
139
- # Recognize menu preferences explicitly
140
  if menu_preferences == "all":
141
  if "non-vegetarian" in command:
142
  menu_preferences = "non-vegetarian"
143
- return "You have chosen the Non-Vegetarian menu. To view menu say menu"
144
  elif "vegetarian" in command and "non-vegetarian" not in command:
145
  menu_preferences = "vegetarian"
146
- return "You have chosen the Vegetarian menu. To view menu say menu"
147
  elif "guilt-free" in command:
148
  menu_preferences = "guilt-free"
149
- return "You have chosen the Guilt-Free menu. To view menu say menu"
150
  elif "all" in command:
151
  menu_preferences = "all"
152
- return "You have chosen the complete menu. To view menu say menu"
153
 
154
- # Filtered menu based on preference
155
  menu = menus.get(menu_preferences, menus["all"])
156
 
157
- # Handle "remove" command explicitly
158
- if "remove" in command:
 
 
 
 
 
 
 
 
 
 
159
  item = command.replace("remove", "").strip()
160
  closest_match = process.extractOne(item, list(cart.keys()), scorer=fuzz.token_set_ratio)
161
  if closest_match and closest_match[1] > 60:
162
  matched_item = closest_match[0]
163
- del cart[matched_item] # Remove the item from the cart
164
- return f"{matched_item.capitalize()} has been removed from your cart. Current cart: {dict(cart)}."
 
 
 
 
165
  return "Sorry, that item is not in your cart."
166
 
167
- # Handle quantity adjustments
168
- if "*" in command:
169
- try:
170
- item, quantity = command.split("*")
171
- item = item.strip()
172
- quantity = int(quantity.strip())
173
- closest_match = process.extractOne(item, menu, scorer=fuzz.token_set_ratio)
174
- if closest_match and closest_match[1] > 60:
175
- matched_item = closest_match[0]
176
- if quantity > 0:
177
- cart[matched_item] = quantity
178
- return f"The quantity of {matched_item} has been updated to {quantity}. Current cart: {dict(cart)}."
179
- elif matched_item in cart:
180
- del cart[matched_item]
181
- return f"{matched_item.capitalize()} has been removed from your cart. Current cart: {dict(cart)}."
182
- return "Sorry, I couldn't recognize the item. Could you try again?"
183
- except ValueError:
184
- return "Invalid quantity format. Please say the item name followed by * and the quantity."
 
 
 
185
 
186
- # Add items to the cart
187
- if any(item in command for item in menu):
188
  closest_match = process.extractOne(command, menu, scorer=fuzz.token_set_ratio)
189
  if closest_match and closest_match[1] > 60:
190
  matched_item = closest_match[0]
191
  cart[matched_item] = cart.get(matched_item, 0) + 1
192
- return f"{matched_item.capitalize()} added to your cart. Current cart: {dict(cart)}. To finalize say final order"
193
  return "Sorry, I couldn't recognize the item. Could you try again?"
194
 
195
- # Handle final order
196
- if "final order" in command:
197
  if cart:
198
  total = sum(prices[item] * count for item, count in cart.items())
199
- response = f"Your final order is: {', '.join(f'{item} x{count}' for item, count in cart.items())}. Your total bill is ${total}. Thank you for ordering! To exit this conversation say nothing or goodbye!"
200
  cart.clear()
201
  return response
202
  return "Your cart is empty. Please add items to your cart first."
203
 
204
- # Handle exit
205
- if "no" in command or "nothing" in command or "goodbye" in command:
206
  cart.clear()
207
- menu_preferences = "all"
208
  return "Goodbye! Thank you for using AI Dining Assistant."
209
 
210
  return "Sorry, I couldn't understand that. Please try again."
@@ -341,5 +349,6 @@ html_code = """
341
  </body>
342
  </html>
343
  """
 
344
  if __name__ == "__main__":
345
  app.run(host="0.0.0.0", port=7860)
 
4
  import os
5
  import ffmpeg
6
  from fuzzywuzzy import process, fuzz
 
7
  from metaphone import doublemetaphone
8
  import logging
9
 
 
11
  logging.basicConfig(level=logging.INFO)
12
 
13
  # Global variables
14
+ cart = {} # Stores items and their quantities in the cart
15
+ menu_preferences = "all" # Tracks the current menu preference
16
+ default_menu_preferences = "all" # To reset menu preferences
17
  prices = {
18
  "samosa": 9,
19
  "onion pakoda": 10,
 
21
  "chicken biryani": 14,
22
  "mutton biryani": 16,
23
  "veg biryani": 12,
24
+ "paneer butter": 10,
25
  "fish curry": 12,
26
  "chicken manchurian": 14,
27
  "veg manchurian": 12,
28
  "chilli chicken": 14,
29
+ "paneer biryani": 13,
30
  "chicken curry": 14
31
  }
32
  menus = {
33
  "all": list(prices.keys()),
34
  "vegetarian": [
35
+ "samosa", "onion pakoda", "chilli gobi", "veg biryani", "paneer butter", "veg manchurian", "paneer biryani"
36
  ],
37
  "non-vegetarian": [
38
  "chicken biryani", "mutton biryani", "fish curry", "chicken manchurian", "chilli chicken", "chicken curry"
 
48
  def reset_cart():
49
  global cart, menu_preferences
50
  cart = {}
51
+ menu_preferences = default_menu_preferences # Reset menu preferences
52
  return "Cart reset successfully."
53
 
54
  @app.route("/process-audio", methods=["POST"])
55
  def process_audio():
56
  try:
57
+ # Handle audio input
58
  audio_file = request.files.get("audio")
59
  if not audio_file:
60
  return jsonify({"response": "No audio file provided."}), 400
61
 
62
+ # Save audio file and convert to WAV format
63
  temp_file = NamedTemporaryFile(delete=False, suffix=".webm")
64
  audio_file.save(temp_file.name)
65
 
66
  converted_file = NamedTemporaryFile(delete=False, suffix=".wav")
67
  ffmpeg.input(temp_file.name).output(
68
+ converted_file.name, acodec="pcm_s16le", ac=1, ar="16000"
69
  ).run(overwrite_output=True)
70
 
71
+ # Recognize speech
72
  recognizer = sr.Recognizer()
73
  recognizer.dynamic_energy_threshold = True
74
  recognizer.energy_threshold = 100
 
 
 
 
75
  with sr.AudioFile(converted_file.name) as source:
76
  recognizer.adjust_for_ambient_noise(source, duration=1)
77
  audio_data = recognizer.record(source)
78
 
79
+ raw_command = recognizer.recognize_google(audio_data).lower()
 
 
 
 
 
 
 
 
 
 
 
80
  logging.info(f"Raw recognized command: {raw_command}")
81
 
82
+ # Preprocess the command
83
  all_menu_items = menus["all"]
84
  command = preprocess_command(raw_command, all_menu_items)
85
 
86
+ # Process the command and get a response
87
  response = process_command(command)
88
 
89
+ except sr.UnknownValueError:
90
+ response = "Sorry, I couldn't understand. Please try again."
91
  except Exception as e:
92
  response = f"An error occurred: {str(e)}"
93
  finally:
 
98
 
99
  def preprocess_command(command, menu_items):
100
  """
101
+ Preprocess the user command to improve matching:
102
+ - Use fuzzy matching for menu items.
103
+ - Use phonetic matching as a fallback.
104
  """
105
  def phonetic_match(word, options):
106
  word_phonetic = doublemetaphone(word)[0]
 
122
  return match
123
 
124
  return command
125
+
126
  def process_command(command):
127
+ """
128
+ Process the user command based on the current menu and cart.
129
+ """
130
  global cart, menu_preferences
131
  command = command.lower()
132
 
133
+ # Handle menu preferences
134
  if menu_preferences == "all":
135
  if "non-vegetarian" in command:
136
  menu_preferences = "non-vegetarian"
137
+ return "You have chosen the Non-Vegetarian menu. To view the menu, say 'menu'."
138
  elif "vegetarian" in command and "non-vegetarian" not in command:
139
  menu_preferences = "vegetarian"
140
+ return "You have chosen the Vegetarian menu. To view the menu, say 'menu'."
141
  elif "guilt-free" in command:
142
  menu_preferences = "guilt-free"
143
+ return "You have chosen the Guilt-Free menu. To view the menu, say 'menu'."
144
  elif "all" in command:
145
  menu_preferences = "all"
146
+ return "You have chosen the complete menu. To view the menu, say 'menu'."
147
 
148
+ # Handle commands related to the current menu
149
  menu = menus.get(menu_preferences, menus["all"])
150
 
151
+ if "menu" in command:
152
+ return f"Here is your menu: {', '.join(menu)}. To select an item, say the item name."
153
+
154
+ elif "price of" in command:
155
+ item = command.replace("price of", "").strip()
156
+ closest_match = process.extractOne(item, prices.keys(), scorer=fuzz.token_set_ratio)
157
+ if closest_match and closest_match[1] > 60:
158
+ matched_item = closest_match[0]
159
+ return f"The price of {matched_item} is ${prices[matched_item]}."
160
+ return "Sorry, I couldn't find that item in the menu."
161
+
162
+ elif "remove" in command:
163
  item = command.replace("remove", "").strip()
164
  closest_match = process.extractOne(item, list(cart.keys()), scorer=fuzz.token_set_ratio)
165
  if closest_match and closest_match[1] > 60:
166
  matched_item = closest_match[0]
167
+ if cart[matched_item] > 1:
168
+ cart[matched_item] -= 1
169
+ return f"One {matched_item} has been removed from your cart. Current cart: {dict(cart)}."
170
+ else:
171
+ del cart[matched_item]
172
+ return f"{matched_item.capitalize()} has been removed from your cart. Current cart: {dict(cart)}."
173
  return "Sorry, that item is not in your cart."
174
 
175
+ elif "increase" in command:
176
+ item = command.replace("increase", "").strip()
177
+ closest_match = process.extractOne(item, list(cart.keys()), scorer=fuzz.token_set_ratio)
178
+ if closest_match and closest_match[1] > 60:
179
+ matched_item = closest_match[0]
180
+ cart[matched_item] += 1
181
+ return f"Quantity of {matched_item} increased to {cart[matched_item]}. Current cart: {dict(cart)}."
182
+ return "Sorry, that item is not in your cart."
183
+
184
+ elif "decrease" in command:
185
+ item = command.replace("decrease", "").strip()
186
+ closest_match = process.extractOne(item, list(cart.keys()), scorer=fuzz.token_set_ratio)
187
+ if closest_match and closest_match[1] > 60:
188
+ matched_item = closest_match[0]
189
+ if cart[matched_item] > 1:
190
+ cart[matched_item] -= 1
191
+ return f"Quantity of {matched_item} decreased to {cart[matched_item]}. Current cart: {dict(cart)}."
192
+ else:
193
+ del cart[matched_item]
194
+ return f"{matched_item.capitalize()} has been removed from your cart. Current cart: {dict(cart)}."
195
+ return "Sorry, that item is not in your cart."
196
 
197
+ elif any(item in command for item in menu):
 
198
  closest_match = process.extractOne(command, menu, scorer=fuzz.token_set_ratio)
199
  if closest_match and closest_match[1] > 60:
200
  matched_item = closest_match[0]
201
  cart[matched_item] = cart.get(matched_item, 0) + 1
202
+ return f"{matched_item.capitalize()} added to your cart. Current cart: {dict(cart)}. To finalize, say 'final order'."
203
  return "Sorry, I couldn't recognize the item. Could you try again?"
204
 
205
+ elif "final order" in command:
 
206
  if cart:
207
  total = sum(prices[item] * count for item, count in cart.items())
208
+ response = f"Your final order is: {', '.join(f'{item} x{count}' for item, count in cart.items())}. Your total bill is ${total}. Thank you for ordering! To exit this conversation, say 'goodbye'."
209
  cart.clear()
210
  return response
211
  return "Your cart is empty. Please add items to your cart first."
212
 
213
+ elif "no" in command or "nothing" in command or "goodbye" in command:
 
214
  cart.clear()
215
+ menu_preferences = default_menu_preferences
216
  return "Goodbye! Thank you for using AI Dining Assistant."
217
 
218
  return "Sorry, I couldn't understand that. Please try again."
 
349
  </body>
350
  </html>
351
  """
352
+
353
  if __name__ == "__main__":
354
  app.run(host="0.0.0.0", port=7860)