nagasurendra commited on
Commit
b2c4de5
·
verified ·
1 Parent(s): 38b65de

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +141 -156
app.py CHANGED
@@ -3,15 +3,15 @@ import speech_recognition as sr
3
  from tempfile import NamedTemporaryFile
4
  import os
5
  import ffmpeg
6
- import logging
7
- from werkzeug.exceptions import BadRequest
8
  from fuzzywuzzy import process
 
 
9
 
10
  app = Flask(__name__)
11
  logging.basicConfig(level=logging.INFO)
12
 
13
  # Global variables
14
- cart = []
15
  menu_preferences = "all"
16
  prices = {
17
  "samosa": 9,
@@ -39,6 +39,143 @@ menus = {
39
  "guilt-free": ["samosa", "onion pakoda"]
40
  }
41
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  html_code = """
43
  <!DOCTYPE html>
44
  <html lang="en">
@@ -171,157 +308,5 @@ html_code = """
171
  </body>
172
  </html>
173
  """
174
- import phonetics
175
- from fuzzywuzzy import process
176
-
177
- def preprocess_command(command, menu_items):
178
- """
179
- Preprocess the user command to improve recognition accuracy.
180
- - Phonetic normalization (handles "paneer" vs. "panner").
181
- - Fuzzy matching to correct minor variations.
182
- """
183
- # Phonetic normalization
184
- def phonetic_match(word, options):
185
- word_phonetic = phonetics.metaphone(word)
186
- for option in options:
187
- if phonetics.metaphone(option) == word_phonetic:
188
- return option
189
- return None
190
-
191
- # Fuzzy matching for the closest match
192
- closest_match = process.extractOne(command, menu_items)
193
- if closest_match and closest_match[1] > 70: # Fuzzy match threshold
194
- return closest_match[0]
195
-
196
- # Fallback to phonetic matching
197
- words = command.split()
198
- for word in words:
199
- match = phonetic_match(word, menu_items)
200
- if match:
201
- return match
202
-
203
- # If no matches found, return the original command
204
- return command
205
-
206
- @app.route('/')
207
- def index():
208
- return render_template_string(html_code)
209
-
210
- @app.route('/reset-cart', methods=['GET'])
211
- def reset_cart():
212
- global cart
213
- global menu_preferences
214
- cart = []
215
- menu_preferences = "all"
216
- return "Cart reset successfully."
217
-
218
- @app.route('/process-audio', methods=['POST'])
219
- def process_audio():
220
- try:
221
- audio_file = request.files.get('audio')
222
- if not audio_file:
223
- raise BadRequest("No audio file provided.")
224
-
225
- temp_file = NamedTemporaryFile(delete=False, suffix=".webm")
226
- audio_file.save(temp_file.name)
227
-
228
- if os.path.getsize(temp_file.name) == 0:
229
- raise BadRequest("Uploaded audio file is empty.")
230
-
231
- converted_file = NamedTemporaryFile(delete=False, suffix=".wav")
232
- ffmpeg.input(temp_file.name).output(
233
- converted_file.name, acodec='pcm_s16le', ac=1, ar='16000'
234
- ).run(overwrite_output=True)
235
-
236
- recognizer = sr.Recognizer()
237
- recognizer.dynamic_energy_threshold = True # Enable dynamic threshold
238
- recognizer.energy_threshold = 100 # Lower threshold for better sensitivity
239
-
240
- with sr.AudioFile(converted_file.name) as source:
241
- audio_data = recognizer.record(source)
242
- try:
243
- raw_command = recognizer.recognize_google(audio_data).lower()
244
- logging.info(f"Raw recognized command: {raw_command}")
245
-
246
- # Preprocess the command
247
- all_menu_items = menus["all"]
248
- preprocessed_command = preprocess_command(raw_command, all_menu_items)
249
- logging.info(f"Preprocessed command: {preprocessed_command}")
250
-
251
- # Process the command with your existing function
252
- response = process_command(preprocessed_command)
253
- except sr.UnknownValueError:
254
- response = "Sorry, I couldn't understand. Please try again."
255
-
256
- return jsonify({"response": response})
257
-
258
- except BadRequest as br:
259
- return jsonify({"response": f"Bad Request: {str(br)}"}), 400
260
- except Exception as e:
261
- return jsonify({"response": f"An error occurred: {str(e)}"}), 500
262
- finally:
263
- os.unlink(temp_file.name)
264
- os.unlink(converted_file.name)
265
-
266
-
267
- def process_command(command):
268
- global cart, menu_preferences
269
- command = command.lower()
270
-
271
- # Recognize menu preferences
272
- if menu_preferences == "all":
273
- if "vegetarian" in command and "non-vegetarian" not in command:
274
- menu_preferences = "vegetarian"
275
- return "You have chosen the Vegetarian menu. To view menu say menu"
276
- elif "non-vegetarian" in command:
277
- menu_preferences = "non-vegetarian"
278
- return "You have chosen the Non-Vegetarian menu. To view menu say menu"
279
- elif "guilt-free" in command:
280
- menu_preferences = "guilt-free"
281
- return "You have chosen the Guilt-Free menu. To view menu say menu"
282
- elif "all" in command:
283
- menu_preferences = "all"
284
- return "You have chosen the complete menu. To view menu say menu"
285
-
286
- # Filtered menu based on preference
287
- menu = menus.get(menu_preferences, menus["all"])
288
-
289
- if "menu" in command:
290
- return f"Here is your menu: {', '.join(menu)}. To select an item say item name."
291
- elif "price of" in command:
292
- item = command.replace("price of", "").strip()
293
- closest_match = process.extractOne(item, prices.keys())
294
- if closest_match and closest_match[1] > 60: # Match threshold
295
- matched_item = closest_match[0]
296
- return f"The price of {matched_item} is ${prices[matched_item]}."
297
- return "Sorry, I couldn't find that item in the menu."
298
- elif "remove" in command:
299
- item = command.replace("remove", "").strip()
300
- closest_match = process.extractOne(item, cart)
301
- if closest_match and closest_match[1] > 80:
302
- matched_item = closest_match[0]
303
- cart.remove(matched_item)
304
- return f"{matched_item.capitalize()} has been removed from your cart."
305
- return "Sorry, that item is not in your cart."
306
- elif any(item in command for item in menu):
307
- closest_match = process.extractOne(command, menu)
308
- if closest_match and closest_match[1] > 80: # Fuzzy match threshold
309
- matched_item = closest_match[0]
310
- cart.append(matched_item)
311
- return f"{matched_item.capitalize()} added to your cart. Your cart now has: {', '.join(cart)}. To add another item say item name. To submit your order say final order."
312
- return "Sorry, I couldn't recognize the item. Could you try again?"
313
- elif "final order" in command:
314
- if cart:
315
- total = sum(prices[item] for item in cart if item in prices)
316
- response = f"Your final order is: {', '.join(cart)}. Your total bill is ${total}. Thank you for ordering!"
317
- cart.clear()
318
- return response
319
- return "Your cart is empty. Please add items to your cart first."
320
- elif "no" in command or "nothing" in command or "goodbye" in command:
321
- cart.clear()
322
- menu_preferences = "all"
323
- return "Goodbye! Thank you for using AI Dining Assistant."
324
- return "Sorry, I couldn't understand that. Please try again."
325
-
326
  if __name__ == "__main__":
327
- app.run(host="0.0.0.0", port=7860)
 
3
  from tempfile import NamedTemporaryFile
4
  import os
5
  import ffmpeg
 
 
6
  from fuzzywuzzy import process
7
+ import phonetics
8
+ import logging
9
 
10
  app = Flask(__name__)
11
  logging.basicConfig(level=logging.INFO)
12
 
13
  # Global variables
14
+ cart = {}
15
  menu_preferences = "all"
16
  prices = {
17
  "samosa": 9,
 
39
  "guilt-free": ["samosa", "onion pakoda"]
40
  }
41
 
42
+ @app.route("/")
43
+ def index():
44
+ return render_template_string(html_code)
45
+
46
+ @app.route("/reset-cart", methods=["GET"])
47
+ def reset_cart():
48
+ global cart, menu_preferences
49
+ cart = {}
50
+ menu_preferences = "all"
51
+ return "Cart reset successfully."
52
+
53
+ @app.route("/process-audio", methods=["POST"])
54
+ def process_audio():
55
+ try:
56
+ audio_file = request.files.get("audio")
57
+ if not audio_file:
58
+ return jsonify({"response": "No audio file provided."}), 400
59
+
60
+ temp_file = NamedTemporaryFile(delete=False, suffix=".webm")
61
+ audio_file.save(temp_file.name)
62
+
63
+ converted_file = NamedTemporaryFile(delete=False, suffix=".wav")
64
+ ffmpeg.input(temp_file.name).output(
65
+ converted_file.name, acodec="pcm_s16le", ac=1, ar="16000"
66
+ ).run(overwrite_output=True)
67
+
68
+ recognizer = sr.Recognizer()
69
+ recognizer.dynamic_energy_threshold = True
70
+ recognizer.energy_threshold = 100 # Sensitive for low audio levels
71
+
72
+ with sr.AudioFile(converted_file.name) as source:
73
+ audio_data = recognizer.record(source)
74
+ raw_command = recognizer.recognize_google(audio_data).lower()
75
+ logging.info(f"Raw recognized command: {raw_command}")
76
+
77
+ # Preprocess command
78
+ all_menu_items = menus["all"]
79
+ command = preprocess_command(raw_command, all_menu_items)
80
+
81
+ # Pass preprocessed command to process_command
82
+ response = process_command(command)
83
+
84
+ except sr.UnknownValueError:
85
+ response = "Sorry, I couldn't understand. Please try again."
86
+ except Exception as e:
87
+ response = f"An error occurred: {str(e)}"
88
+ finally:
89
+ os.unlink(temp_file.name)
90
+ os.unlink(converted_file.name)
91
+
92
+ return jsonify({"response": response})
93
+
94
+
95
+ def preprocess_command(command, menu_items):
96
+ """
97
+ Preprocess the user command:
98
+ - Normalize speech for accents and speed using fuzzy matching.
99
+ - Phonetically match menu items.
100
+ """
101
+ def phonetic_match(word, options):
102
+ word_phonetic = phonetics.metaphone(word)
103
+ for option in options:
104
+ if phonetics.metaphone(option) == word_phonetic:
105
+ return option
106
+ return None
107
+
108
+ # First, try fuzzy matching
109
+ closest_match = process.extractOne(command, menu_items)
110
+ if closest_match and closest_match[1] > 70: # Adjust fuzzy match threshold
111
+ return closest_match[0]
112
+
113
+ # Fallback to phonetic matching
114
+ words = command.split()
115
+ for word in words:
116
+ match = phonetic_match(word, menu_items)
117
+ if match:
118
+ return match
119
+
120
+ return command
121
+
122
+
123
+ def process_command(command):
124
+ global cart, menu_preferences
125
+ command = command.lower()
126
+
127
+ if menu_preferences == "all":
128
+ if "vegetarian" in command and "non-vegetarian" not in command:
129
+ menu_preferences = "vegetarian"
130
+ return "You have chosen the Vegetarian menu. To view menu say menu"
131
+ elif "non-vegetarian" in command:
132
+ menu_preferences = "non-vegetarian"
133
+ return "You have chosen the Non-Vegetarian menu. To view menu say menu"
134
+ elif "guilt-free" in command:
135
+ menu_preferences = "guilt-free"
136
+ return "You have chosen the Guilt-Free menu. To view menu say menu"
137
+ elif "all" in command:
138
+ menu_preferences = "all"
139
+ return "You have chosen the complete menu. To view menu say menu"
140
+
141
+ menu = menus.get(menu_preferences, menus["all"])
142
+
143
+ if "menu" in command:
144
+ return f"Here is your menu: {', '.join(menu)}. To select an item say item name."
145
+ elif "price of" in command:
146
+ item = command.replace("price of", "").strip()
147
+ closest_match = process.extractOne(item, prices.keys())
148
+ if closest_match and closest_match[1] > 70:
149
+ matched_item = closest_match[0]
150
+ return f"The price of {matched_item} is ${prices[matched_item]}."
151
+ return "Sorry, I couldn't find that item in the menu."
152
+ elif "remove" in command:
153
+ item = command.replace("remove", "").strip()
154
+ if item in cart:
155
+ del cart[item]
156
+ return f"{item.capitalize()} has been removed from your cart."
157
+ return "Sorry, that item is not in your cart."
158
+ elif any(item in command for item in menu):
159
+ closest_match = process.extractOne(command, menu)
160
+ if closest_match and closest_match[1] > 70:
161
+ matched_item = closest_match[0]
162
+ cart[matched_item] = cart.get(matched_item, 0) + 1
163
+ return f"{matched_item.capitalize()} added to your cart. Current cart: {dict(cart)}."
164
+ return "Sorry, I couldn't recognize the item. Could you try again?"
165
+ elif "final order" in command:
166
+ if cart:
167
+ total = sum(prices[item] * count for item, count in cart.items())
168
+ 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!"
169
+ cart.clear()
170
+ return response
171
+ return "Your cart is empty. Please add items to your cart first."
172
+ elif "no" in command or "nothing" in command or "goodbye" in command:
173
+ cart.clear()
174
+ menu_preferences = "all"
175
+ return "Goodbye! Thank you for using AI Dining Assistant."
176
+ return "Sorry, I couldn't understand that. Please try again."
177
+
178
+
179
  html_code = """
180
  <!DOCTYPE html>
181
  <html lang="en">
 
308
  </body>
309
  </html>
310
  """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
311
  if __name__ == "__main__":
312
+ app.run(host="0.0.0.0", port=7860)