nagasurendra commited on
Commit
3690a94
·
verified ·
1 Parent(s): 4c9caa0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +27 -291
app.py CHANGED
@@ -1,302 +1,30 @@
1
- from flask import Flask, render_template_string, request, jsonify
2
- 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,
18
- "onion pakoda": 10,
19
- "chilli gobi": 12,
20
- "chicken biryani": 14,
21
- "mutton biryani": 16,
22
- "veg biryani": 12,
23
- "panner butter": 10,
24
- "fish curry": 12,
25
- "chicken manchurian": 14,
26
- "veg manchurian": 12,
27
- "chilli chicken": 14,
28
- "panner biryani": 13,
29
- "chicken curry": 14
30
- }
31
- menus = {
32
- "all": list(prices.keys()),
33
- "vegetarian": [
34
- "samosa", "onion pakoda", "chilli gobi", "veg biryani", "panner butter", "veg manchurian", "panner biryani"
35
- ],
36
- "non-vegetarian": [
37
- "chicken biryani", "mutton biryani", "fish curry", "chicken manchurian", "chilli chicken", "chicken curry"
38
- ],
39
- "guilt-free": ["samosa", "onion pakoda"]
40
- }
41
-
42
- html_code = """
43
- <!DOCTYPE html>
44
- <html lang="en">
45
- <head>
46
- <meta charset="UTF-8">
47
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
48
- <title>AI Dining Assistant</title>
49
- <style>
50
- body {
51
- display: flex;
52
- flex-direction: column;
53
- align-items: center;
54
- justify-content: center;
55
- min-height: 100vh;
56
- margin: 0;
57
- font-family: Arial, sans-serif;
58
- background-color: #f4f4f9;
59
- }
60
- h1 {
61
- color: #333;
62
- }
63
- .mic-button {
64
- font-size: 2rem;
65
- padding: 1rem 2rem;
66
- color: white;
67
- background-color: #007bff;
68
- border: none;
69
- border-radius: 50px;
70
- cursor: pointer;
71
- transition: background-color 0.3s;
72
- }
73
- .mic-button:hover {
74
- background-color: #0056b3;
75
- }
76
- .status, .response {
77
- margin-top: 1rem;
78
- text-align: center;
79
- color: #555;
80
- font-size: 1.2rem;
81
- }
82
- .response {
83
- background-color: #e8e8ff;
84
- padding: 1rem;
85
- border-radius: 10px;
86
- box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
87
- display: none;
88
- }
89
- </style>
90
- </head>
91
- <body>
92
- <h1>AI Dining Assistant</h1>
93
- <button class="mic-button" id="mic-button">🎤</button>
94
- <div class="status" id="status">Press the mic button to start...</div>
95
- <div class="response" id="response">Response will appear here...</div>
96
- <script>
97
- const micButton = document.getElementById('mic-button');
98
- const status = document.getElementById('status');
99
- const response = document.getElementById('response');
100
- let mediaRecorder;
101
- let audioChunks = [];
102
- let isConversationActive = false;
103
- micButton.addEventListener('click', () => {
104
- if (!isConversationActive) {
105
- isConversationActive = true;
106
- startConversation();
107
- }
108
- });
109
- function startConversation() {
110
- const utterance = new SpeechSynthesisUtterance('Please choose your preference: All, Vegetarian, Non-Vegetarian, or Guilt-Free.');
111
- speechSynthesis.speak(utterance);
112
- utterance.onend = () => {
113
- status.textContent = 'Listening...';
114
- startListening();
115
- };
116
- }
117
- function startListening() {
118
- navigator.mediaDevices.getUserMedia({ audio: true }).then(stream => {
119
- mediaRecorder = new MediaRecorder(stream, { mimeType: 'audio/webm;codecs=opus' });
120
- mediaRecorder.start();
121
- audioChunks = [];
122
- mediaRecorder.ondataavailable = event => audioChunks.push(event.data);
123
- mediaRecorder.onstop = async () => {
124
- const audioBlob = new Blob(audioChunks, { type: 'audio/webm' });
125
- const formData = new FormData();
126
- formData.append('audio', audioBlob);
127
- status.textContent = 'Processing...';
128
- try {
129
- const result = await fetch('/process-audio', { method: 'POST', body: formData });
130
- const data = await result.json();
131
- response.textContent = data.response;
132
- response.style.display = 'block';
133
- const utterance = new SpeechSynthesisUtterance(data.response);
134
- speechSynthesis.speak(utterance);
135
- utterance.onend = () => {
136
- console.log("Speech synthesis completed.");
137
- if (data.response.includes("Goodbye")) {
138
- status.textContent = 'Conversation ended. Press the mic button to start again.';
139
- isConversationActive = false;
140
- fetch('/reset-cart'); // Reset the cart dynamically on end
141
- } else if (data.response.includes("Your order is complete")) {
142
- status.textContent = 'Order complete. Thank you for using AI Dining Assistant.';
143
- isConversationActive = false;
144
- fetch('/reset-cart'); // Reset the cart after final order
145
- } else {
146
- status.textContent = 'Listening...';
147
- setTimeout(() => {
148
- startListening();
149
- }, 2000);
150
- }
151
- };
152
- utterance.onerror = (e) => {
153
- console.error("Speech synthesis error:", e.error);
154
- status.textContent = 'Error with speech output.';
155
- isConversationActive = false;
156
- };
157
- } catch (error) {
158
- response.textContent = 'Sorry, I could not understand. Please try again.';
159
- response.style.display = 'block';
160
- status.textContent = 'Press the mic button to restart the conversation.';
161
- isConversationActive = false;
162
- }
163
- };
164
- setTimeout(() => mediaRecorder.stop(), 5000);
165
- }).catch(() => {
166
- status.textContent = 'Microphone access denied.';
167
- isConversationActive = false;
168
- });
169
- }
170
- </script>
171
- </body>
172
- </html>
173
- """
174
-
175
- @app.route('/')
176
- def index():
177
- return render_template_string(html_code)
178
-
179
- @app.route('/reset-cart', methods=['GET'])
180
- def reset_cart():
181
- global cart
182
- global menu_preferences
183
- cart = []
184
- menu_preferences = "all"
185
- return "Cart reset successfully."
186
-
187
-
188
- @app.route('/process-audio', methods=['POST'])
189
- def process_audio():
190
- try:
191
- # Step 1: Get the audio file from the request
192
- audio_file = request.files.get('audio')
193
- if not audio_file:
194
- raise BadRequest("No audio file provided. Please check if the microphone is working.")
195
-
196
- # Step 2: Save the raw audio for debugging purposes
197
- raw_audio_path = "debug_audio.webm"
198
- audio_file.save(raw_audio_path)
199
-
200
- # Step 3: Convert .webm to .wav format for recognition
201
- wav_audio_path = "debug_audio.wav"
202
- ffmpeg.input(raw_audio_path).output(
203
- wav_audio_path, acodec='pcm_s16le', ac=1, ar='16000'
204
- ).run(overwrite_output=True)
205
-
206
- # Step 4: Preprocess the audio file for noise reduction (optional)
207
- preprocessed_audio_path = "enhanced_audio.wav"
208
- preprocess_audio(wav_audio_path, preprocessed_audio_path)
209
-
210
- # Step 5: Use the SpeechRecognition library for transcription
211
- recognizer = sr.Recognizer()
212
- recognizer.energy_threshold = 300 # Adjust for low-volume audio
213
- with sr.AudioFile(preprocessed_audio_path) as source:
214
- audio_data = recognizer.record(source)
215
- try:
216
- # Attempt to recognize speech
217
- command = recognizer.recognize_google(audio_data)
218
- logging.info(f"Recognized command: {command}")
219
- print(f"Recognized command: {command}")
220
- response = process_command(command)
221
- except sr.UnknownValueError:
222
- # Handle unrecognizable audio
223
- response = "Sorry, I could not understand. Please speak clearly."
224
- logging.warning("Speech could not be understood.")
225
- command = "Unrecognized"
226
- except sr.RequestError as e:
227
- # Handle API issues
228
- response = "Sorry, there was an issue with the speech recognition service."
229
- logging.error(f"Speech recognition service error: {str(e)}")
230
- command = "Recognition Service Error"
231
-
232
- # Return the response along with the recognized command (or errors)
233
- return jsonify({
234
- "response": response,
235
- "recognized_command": command
236
- })
237
-
238
- except BadRequest as br:
239
- # Handle missing audio file or bad requests
240
- logging.error(f"Bad request: {str(br)}")
241
- return jsonify({"response": f"Bad Request: {str(br)}"}), 400
242
- except Exception as e:
243
- # Handle unexpected errors
244
- logging.error(f"An unexpected error occurred: {str(e)}")
245
- return jsonify({"response": f"An error occurred: {str(e)}"}), 500
246
- finally:
247
- # Clean up temporary files
248
- for temp_file in [raw_audio_path, wav_audio_path, preprocessed_audio_path]:
249
- if os.path.exists(temp_file):
250
- os.unlink(temp_file)
251
-
252
- def preprocess_audio(input_path, output_path):
253
- """
254
- Enhance audio by normalizing volume and reducing noise.
255
- """
256
- from pydub import AudioSegment
257
-
258
- audio = AudioSegment.from_file(input_path)
259
- audio = audio.normalize() # Normalize volume
260
- audio = audio.high_pass_filter(200) # Remove low-frequency noise
261
- audio.export(output_path, format="wav")
262
-
263
-
264
-
265
-
266
- # Add this to the imports
267
  def process_command(command):
268
  global cart, menu_preferences
269
  command = command.lower()
270
-
271
  # Recognize menu preferences first
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."
276
  elif "non-vegetarian" in command:
277
  menu_preferences = "non-vegetarian"
278
- return "You have chosen the Non-Vegetarian menu."
279
  elif "guilt-free" in command:
280
  menu_preferences = "guilt-free"
281
- return "You have chosen the Guilt-Free menu."
282
  elif "all" in command:
283
  menu_preferences = "all"
284
- return "You have chosen the complete menu."
285
-
286
  # Use filtered menu based on preference
287
  menu = menus.get(menu_preferences, menus["all"])
288
 
289
- # Greet users if they say 'Hi' or 'Hello'
290
- if command in ["hi", "hello", "hey"]:
291
- return "Hello! Welcome to AI Dining Assistant. Please choose your menu preference: All, Vegetarian, Non-Vegetarian, or Guilt-Free."
292
-
293
- # Handle general unrelated topics politely
294
- if "how are you" in command or "what is this" in command:
295
- return "I'm here to help you order food. Please let me know your preferences or say 'menu' to see options."
296
-
297
- # Suggest menu for unrelated inputs
298
  if "menu" in command:
299
- return f"Here is your menu: {', '.join(menu)}."
 
300
  elif "price of" in command:
301
  item = command.replace("price of", "").strip()
302
  closest_match = process.extractOne(item, prices.keys())
@@ -304,29 +32,37 @@ def process_command(command):
304
  matched_item = closest_match[0]
305
  return f"The price of {matched_item} is ${prices[matched_item]}."
306
  return "Sorry, I couldn't find that item in the menu."
 
 
 
 
 
 
 
 
 
 
307
  elif any(item in command for item in menu):
308
- matched_item = next((item for item in menu if item in command), None)
309
- if matched_item:
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. To know the price of an item say price of item name. To remove an item say remove item name."
 
312
  else:
313
  return "Sorry, I couldn't recognize the item. Could you try again?"
 
314
  elif "final order" in command or "submit" in command:
315
  if cart:
316
  total = sum(prices[item] for item in cart if item in prices)
317
- response = f"Your final order is: {', '.join(cart)}. Your total bill is ${total}. Thank you for ordering! To stop this conversation say nothing or goodbye!"
318
  cart.clear() # Reset the cart after final order
319
  return response
320
  else:
321
  return "Your cart is empty. Please add items to your cart first."
 
322
  elif "no" in command or "nothing" in command or "goodbye" in command:
323
  cart.clear() # Clear cart on exit
324
  menu_preferences = "all"
325
  return "Goodbye! Thank you for using AI Dining Assistant."
326
-
327
- # Default response for unrelated topics
328
- return "I'm sorry, but I can only assist with ordering food from our menu. Please let me know your preferences."
329
-
330
 
331
- if __name__ == "__main__":
332
- app.run(host="0.0.0.0", port=7860)
 
 
 
 
 
 
 
 
1
  from fuzzywuzzy import process
2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  def process_command(command):
4
  global cart, menu_preferences
5
  command = command.lower()
6
+
7
  # Recognize menu preferences first
8
  if menu_preferences == "all":
9
  if "vegetarian" in command and "non-vegetarian" not in command:
10
  menu_preferences = "vegetarian"
11
+ return "You have chosen the Vegetarian menu. To view menu say menu"
12
  elif "non-vegetarian" in command:
13
  menu_preferences = "non-vegetarian"
14
+ return "You have chosen the Non-Vegetarian menu. To view menu say menu"
15
  elif "guilt-free" in command:
16
  menu_preferences = "guilt-free"
17
+ return "You have chosen the Guilt-Free menu. To view menu say menu"
18
  elif "all" in command:
19
  menu_preferences = "all"
20
+ return "You have chosen the complete menu. To view menu say menu"
21
+
22
  # Use filtered menu based on preference
23
  menu = menus.get(menu_preferences, menus["all"])
24
 
 
 
 
 
 
 
 
 
 
25
  if "menu" in command:
26
+ return f"Here is your menu: {', '.join(menu)}. To select an item say item name"
27
+
28
  elif "price of" in command:
29
  item = command.replace("price of", "").strip()
30
  closest_match = process.extractOne(item, prices.keys())
 
32
  matched_item = closest_match[0]
33
  return f"The price of {matched_item} is ${prices[matched_item]}."
34
  return "Sorry, I couldn't find that item in the menu."
35
+
36
+ elif "remove" in command:
37
+ item = command.replace("remove", "").strip()
38
+ closest_match = process.extractOne(item, cart)
39
+ if closest_match and closest_match[1] > 80:
40
+ matched_item = closest_match[0]
41
+ cart.remove(matched_item)
42
+ return f"{matched_item.capitalize()} has been removed from your cart."
43
+ return "Sorry, that item is not in your cart."
44
+
45
  elif any(item in command for item in menu):
46
+ # Fuzzy match for menu items
47
+ matched_item = process.extractOne(command, menu)
48
+ if matched_item and matched_item[1] > 80: # Match threshold
49
+ cart.append(matched_item[0])
50
+ return f"{matched_item[0].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. To know the price of an item say price of item name. To remove an item say remove item name."
51
  else:
52
  return "Sorry, I couldn't recognize the item. Could you try again?"
53
+
54
  elif "final order" in command or "submit" in command:
55
  if cart:
56
  total = sum(prices[item] for item in cart if item in prices)
57
+ response = f"Your final order is: {', '.join(cart)}. Your total bill is ${total}. Thank you for ordering! To stop this conversation say nothing or good bye!"
58
  cart.clear() # Reset the cart after final order
59
  return response
60
  else:
61
  return "Your cart is empty. Please add items to your cart first."
62
+
63
  elif "no" in command or "nothing" in command or "goodbye" in command:
64
  cart.clear() # Clear cart on exit
65
  menu_preferences = "all"
66
  return "Goodbye! Thank you for using AI Dining Assistant."
 
 
 
 
67
 
68
+ return "Sorry, I couldn't understand that. Please try again."