DSatishchandra commited on
Commit
7f2bf77
·
verified ·
1 Parent(s): 0d593cd

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +252 -0
app.py ADDED
@@ -0,0 +1,252 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+
9
+ app = Flask(__name__)
10
+ logging.basicConfig(level=logging.INFO)
11
+
12
+ # Global variables
13
+ cart = [] # To store items, quantities, and prices
14
+ MENU = {
15
+ "Biryanis": {"Chicken Biryani": 250, "Veg Biryani": 200, "Mutton Biryani": 300},
16
+ "Starters": {"Chicken Wings": 220, "Paneer Tikka": 180, "Fish Fingers": 250, "Spring Rolls": 160},
17
+ "Breads": {"Butter Naan": 50, "Garlic Naan": 60, "Roti": 40, "Lachha Paratha": 70},
18
+ "Curries": {"Butter Chicken": 300, "Paneer Butter Masala": 250, "Dal Tadka": 200, "Chicken Tikka Masala": 320},
19
+ "Drinks": {"Coke": 60, "Sprite": 60, "Mango Lassi": 80, "Masala Soda": 70},
20
+ "Desserts": {"Gulab Jamun": 100, "Rasgulla": 90, "Ice Cream": 120, "Brownie with Ice Cream": 180},
21
+ }
22
+ current_category = None
23
+ current_item = None
24
+ awaiting_quantity = False
25
+
26
+ # Extract quantity from command (e.g., "two" -> 2, "three" -> 3, etc.)
27
+ def extract_quantity(command):
28
+ number_words = {
29
+ "one": 1, "two": 2, "three": 3, "four": 4, "five": 5,
30
+ "six": 6, "seven": 7, "eight": 8, "nine": 9, "ten": 10,
31
+ "1": 1, "2": 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7, "8": 8, "9": 9, "10": 10
32
+ }
33
+
34
+ command_words = command.split()
35
+ for word in command_words:
36
+ if word in number_words:
37
+ return number_words[word]
38
+ return None
39
+
40
+ # HTML Template for Frontend
41
+ html_code = """
42
+ <!DOCTYPE html>
43
+ <html lang="en">
44
+ <head>
45
+ <meta charset="UTF-8">
46
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
47
+ <title>AI Dining Assistant</title>
48
+ <style>
49
+ body {
50
+ font-family: Arial, sans-serif;
51
+ text-align: center;
52
+ background-color: #f4f4f9;
53
+ }
54
+ h1 {
55
+ color: #333;
56
+ }
57
+ .mic-button {
58
+ width: 80px;
59
+ height: 80px;
60
+ border-radius: 50%;
61
+ background-color: #007bff;
62
+ color: white;
63
+ font-size: 24px;
64
+ border: none;
65
+ cursor: pointer;
66
+ }
67
+ .status, .response {
68
+ margin-top: 20px;
69
+ }
70
+ </style>
71
+ </head>
72
+ <body>
73
+ <h1>AI Dining Assistant</h1>
74
+ <button class="mic-button" id="mic-button">🎤</button>
75
+ <div class="status" id="status">Press the mic button to start...</div>
76
+ <div class="response" id="response" style="display: none;">Response will appear here...</div>
77
+ <script>
78
+ const micButton = document.getElementById('mic-button');
79
+ const status = document.getElementById('status');
80
+ const response = document.getElementById('response');
81
+ let isListening = false;
82
+ micButton.addEventListener('click', () => {
83
+ if (!isListening) {
84
+ isListening = true;
85
+ greetUser();
86
+ }
87
+ });
88
+ function greetUser() {
89
+ const utterance = new SpeechSynthesisUtterance("Hi. Welcome to Biryani Hub. Can I show you the menu?");
90
+ speechSynthesis.speak(utterance);
91
+ utterance.onend = () => {
92
+ status.textContent = "Listening...";
93
+ startListening();
94
+ };
95
+ }
96
+ async function startListening() {
97
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
98
+ const mediaRecorder = new MediaRecorder(stream, { mimeType: "audio/webm;codecs=opus" });
99
+ const audioChunks = [];
100
+ mediaRecorder.ondataavailable = (event) => audioChunks.push(event.data);
101
+ mediaRecorder.onstop = async () => {
102
+ const audioBlob = new Blob(audioChunks, { type: "audio/webm" });
103
+ const formData = new FormData();
104
+ formData.append("audio", audioBlob);
105
+ status.textContent = "Processing...";
106
+ try {
107
+ const result = await fetch("/process-audio", { method: "POST", body: formData });
108
+ const data = await result.json();
109
+ response.textContent = data.response;
110
+ response.style.display = "block";
111
+ const utterance = new SpeechSynthesisUtterance(data.response);
112
+ speechSynthesis.speak(utterance);
113
+ utterance.onend = () => {
114
+ if (!data.response.includes("Goodbye") && !data.response.includes("final order")) {
115
+ startListening(); // Continue listening
116
+ } else {
117
+ status.textContent = "Conversation ended.";
118
+ isListening = false;
119
+ }
120
+ };
121
+ } catch (error) {
122
+ response.textContent = "Error processing your request. Please try again.";
123
+ status.textContent = "Press the mic button to restart.";
124
+ isListening = false;
125
+ }
126
+ };
127
+ mediaRecorder.start();
128
+ setTimeout(() => mediaRecorder.stop(), 5000); // Stop recording after 5 seconds
129
+ }
130
+ </script>
131
+ </body>
132
+ </html>
133
+ """
134
+
135
+ @app.route("/")
136
+ def index():
137
+ return render_template_string(html_code)
138
+
139
+ @app.route("/process-audio", methods=["POST"])
140
+ def process_audio():
141
+ global current_category, current_item, awaiting_quantity
142
+ try:
143
+ audio_file = request.files.get("audio")
144
+ if not audio_file:
145
+ raise BadRequest("No audio file provided.")
146
+
147
+ temp_file = NamedTemporaryFile(delete=False, suffix=".webm")
148
+ audio_file.save(temp_file.name)
149
+
150
+ if os.path.getsize(temp_file.name) == 0:
151
+ raise BadRequest("Uploaded audio file is empty.")
152
+
153
+ converted_file = NamedTemporaryFile(delete=False, suffix=".wav")
154
+ ffmpeg.input(temp_file.name).output(
155
+ converted_file.name, acodec="pcm_s16le", ac=1, ar="16000"
156
+ ).run(overwrite_output=True)
157
+
158
+ recognizer = sr.Recognizer()
159
+ with sr.AudioFile(converted_file.name) as source:
160
+ audio_data = recognizer.record(source)
161
+ try:
162
+ command = recognizer.recognize_google(audio_data)
163
+ logging.info(f"Recognized command: {command}")
164
+ response = process_command(command)
165
+ except sr.UnknownValueError:
166
+ response = "Sorry, I couldn't understand your command. Could you please repeat?"
167
+ except sr.RequestError as e:
168
+ response = f"Error with the speech recognition service: {e}"
169
+
170
+ return jsonify({"response": response})
171
+
172
+ except BadRequest as br:
173
+ return jsonify({"response": f"Bad Request: {str(br)}"}), 400
174
+ except Exception as e:
175
+ return jsonify({"response": f"An error occurred: {str(e)}"}), 500
176
+ finally:
177
+ os.unlink(temp_file.name)
178
+ os.unlink(converted_file.name)
179
+
180
+ def process_command(command):
181
+ global cart, MENU, current_category, current_item, awaiting_quantity
182
+ command = command.lower()
183
+
184
+ # Handle quantity input
185
+ if awaiting_quantity:
186
+ quantity = extract_quantity(command)
187
+ if quantity:
188
+ cart.append((current_item, MENU[current_category][current_item], quantity))
189
+ awaiting_quantity = False
190
+ item = current_item
191
+ current_item = None
192
+ total = sum(i[1] * i[2] for i in cart)
193
+ cart_summary = ", ".join([f"{i[0]} x{i[2]} (₹{i[1] * i[2]})" for i in cart])
194
+ return f"Added {quantity} x {item} to your cart. Your current cart: {cart_summary}. Total: ₹{total}. Would you like to add more items?"
195
+ else:
196
+ return "Sorry, I couldn't understand the quantity. Please provide a valid quantity."
197
+
198
+ # Handle category selection
199
+ for category, items in MENU.items():
200
+ if category.lower() in command:
201
+ current_category = category
202
+ item_list = ", ".join([f"{item} (₹{price})" for item, price in items.items()])
203
+ return f"{category} menu: {item_list}. What would you like to order?"
204
+
205
+ # Handle item selection with dynamic matching
206
+ if current_category:
207
+ for item in MENU[current_category].keys():
208
+ if item.lower().startswith(command) or command in item.lower():
209
+ current_item = item
210
+ awaiting_quantity = True
211
+ return f"How many quantities of {current_item} would you like?"
212
+
213
+ # Handle item removal
214
+ if "remove" in command:
215
+ for item in cart:
216
+ if item[0].lower() in command:
217
+ cart.remove(item)
218
+ total = sum(i[1] * i[2] for i in cart)
219
+ cart_summary = ", ".join([f"{i[0]} x{i[2]} (₹{i[1] * i[2]})" for i in cart])
220
+ return f"Removed {item[0]} from your cart. Updated cart: {cart_summary}. Total: ₹{total}."
221
+ return "The item you are trying to remove is not in your cart."
222
+
223
+ # Handle final order
224
+ if "final order" in command or "submit" in command:
225
+ if cart:
226
+ order_details = ", ".join([f"{item[0]} x{item[2]} (₹{item[1] * item[2]})" for item in cart])
227
+ total = sum(item[1] * item[2] for item in cart)
228
+ cart.clear()
229
+ return f"Your final order is: {order_details}. Total price: ₹{total}. Thank you for visiting Biryani Hub!"
230
+ else:
231
+ return "Your cart is empty. Please add items before placing the final order."
232
+
233
+ # Handle cart details
234
+ if "cart details" in command:
235
+ if cart:
236
+ cart_summary = "\n".join([f"{i[0]} x{i[2]} (₹{i[1] * i[2]})" for i in cart])
237
+ total = sum(i[1] * i[2] for i in cart)
238
+ return f"Your cart contains:\n{cart_summary}\nTotal: ₹{total}."
239
+ else:
240
+ return "Your cart is empty."
241
+
242
+ # Handle menu request
243
+ if "menu" in command or "yes" in command or "yeah" in command:
244
+ categories = ", ".join(MENU.keys())
245
+ return f"We have the following categories: {categories}. Please select a category to proceed."
246
+
247
+ # Default response
248
+ return "Sorry, I didn't understand that. Please try again."
249
+
250
+
251
+ if __name__ == "__main__":
252
+ app.run(host="0.0.0.0", port=7860)