dschandra commited on
Commit
e71240e
·
verified ·
1 Parent(s): 3287093

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +333 -54
app.py CHANGED
@@ -1,67 +1,346 @@
1
- # Import required libraries
2
- from faster_whisper import WhisperModel
3
- from transformers import pipeline
4
- from bark import generate_audio
5
- from flask import Flask, request, jsonify
 
 
 
 
 
 
 
6
 
7
- # Initialize Flask app
8
  app = Flask(__name__)
 
9
 
10
- # Load models
11
- speech_model = WhisperModel("tiny", device="cuda", compute_type="float16")
12
- nlp_model = pipeline("text-generation", model="gpt-3.5-turbo")
 
 
 
 
 
13
 
14
- @app.route('/process_audio', methods=['POST'])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  def process_audio():
 
16
  try:
17
- # Step 1: Receive the audio file from the user
18
- audio_file = request.files['audio']
19
- audio_path = f"./temp/{audio_file.filename}"
20
- audio_file.save(audio_path)
21
 
22
- # Step 2: Transcribe the audio to text
23
- transcription = transcribe_audio(audio_path)
24
 
25
- # Step 3: Generate a response based on the transcription
26
- response_text = generate_response(transcription)
27
 
28
- # Step 4: Synthesize speech from the response text
29
- response_audio = synthesize_speech(response_text)
 
 
30
 
31
- # Save the response audio to a file
32
- response_audio_path = f"./temp/response_audio.wav"
33
- response_audio.export(response_audio_path, format="wav")
 
 
 
 
 
 
 
 
 
34
 
35
- return jsonify({
36
- "transcription": transcription,
37
- "response_text": response_text,
38
- "response_audio_path": response_audio_path
39
- })
40
  except Exception as e:
41
- return jsonify({"error": str(e)}), 500
42
-
43
- def transcribe_audio(audio_path):
44
- """
45
- Transcribe audio using Whisper.
46
- """
47
- segments, info = speech_model.transcribe(audio_path)
48
- transcription = " ".join([segment.text for segment in segments])
49
- return transcription
50
-
51
- def generate_response(user_input):
52
- """
53
- Generate text response using GPT-3.5-turbo.
54
- """
55
- response = nlp_model(user_input, max_length=100, do_sample=True)
56
- return response[0]['generated_text']
57
-
58
- def synthesize_speech(text):
59
- """
60
- Generate speech audio using Bark.
61
- """
62
- audio_array = generate_audio(text)
63
- return audio_array
64
-
65
- # Run the app
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  if __name__ == "__main__":
67
- app.run(debug=True, host="0.0.0.0", port=5000)
 
1
+ from flask import Flask, render_template_string, request, jsonify
2
+ from simple_salesforce import Salesforce
3
+ import logging
4
+ from tempfile import NamedTemporaryFile
5
+ import os
6
+ import re
7
+ import traceback
8
+ import ffmpeg
9
+ import speech_recognition as sr
10
+ from werkzeug.exceptions import BadRequest
11
+ from datetime import datetime
12
+ from word2number import w2n # Import word-to-number conversion library
13
 
 
14
  app = Flask(__name__)
15
+ logging.basicConfig(level=logging.INFO)
16
 
17
+ # Salesforce connection setup
18
+ sf = Salesforce(
19
+ username='[email protected]',
20
+ password='Sati@1020',
21
+ security_token='sSSjyhInIsUohKpG8sHzty2q',
22
+ consumer_key='3MVG9WVXk15qiz1JbtW1tT9a7Wnkos2RuGamw6p1lC5uPescT5NB2nPygpo6rQ87K1T.zBEn.wR.A6JdgHnIU',
23
+ consumer_secret='A75C6B7801D5D20BED0E46631CF58C4F7FF28E4DAF442FE667553D29C35C0451'
24
+ )
25
 
26
+ # Global variables
27
+ cart = [] # To store items, quantities, prices, and add-ons
28
+ current_category = None
29
+ awaiting_preference = True
30
+ awaiting_quantity = False
31
+ user_email = None # Will be set later once the user provides it
32
+ awaiting_item_selection = False # Flag to know when to ask for item selection
33
+ user_name = None # Will be set once the user provides their name
34
+
35
+ # Function to fetch menu items from Salesforce based on the category filter
36
+ def get_menu_items(category):
37
+ category_filter = ''
38
+
39
+ # Determine the category filter (Veg, Non-Veg, or All)
40
+ if category == 'Veg':
41
+ category_filter = 'Veg'
42
+ elif category == 'Non-Veg':
43
+ category_filter = 'Non veg'
44
+ elif category == 'All':
45
+ category_filter = '' # No filter for 'All'
46
+
47
+ # Query Salesforce based on the category filter
48
+ if category_filter == '':
49
+ query = "SELECT Id, Name, Price__c, Image1__c, Veg_NonVeg__c, Section__c FROM Menu_Item__c"
50
+ else:
51
+ query = f"""
52
+ SELECT Id, Name, Price__c, Image1__c, Veg_NonVeg__c, Section__c
53
+ FROM Menu_Item__c
54
+ WHERE Veg_NonVeg__c = '{category_filter}' OR Veg_NonVeg__c = 'both'
55
+ """
56
+
57
+ # Execute the query
58
+ result = sf.query_all(query)
59
+ return result['records']
60
+
61
+ # Function to save cart and order details into Salesforce
62
+ def save_order_to_salesforce(cart, user_email, total_amount):
63
+ # Prepare the order object
64
+ order_items = ", ".join([f"{item['Name']} x {item['Quantity']}" for item in cart])
65
+ order = {
66
+ 'Customer_Email__c': user_email,
67
+ 'Order_Date_Time__c': datetime.now(),
68
+ 'Order_Items__c': order_items,
69
+ 'Total_Amount__c': total_amount,
70
+ 'Status__c': 'Pending' # Assuming the status is 'Pending' initially
71
+ }
72
+
73
+ # Insert order record into Salesforce
74
+ order_record = sf.Order__c.create(order)
75
+ return order_record
76
+
77
+ # HTML Template for Frontend
78
+ html_code = """
79
+ <!DOCTYPE html>
80
+ <html lang="en">
81
+ <head>
82
+ <meta charset="UTF-8">
83
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
84
+ <title>AI Dining Assistant</title>
85
+ <style>
86
+ body {
87
+ font-family: Arial, sans-serif;
88
+ text-align: center;
89
+ background-color: #f4f4f9;
90
+ }
91
+ h1 {
92
+ color: #333;
93
+ }
94
+ .mic-button {
95
+ width: 80px;
96
+ height: 80px;
97
+ border-radius: 50%;
98
+ background-color: #007bff;
99
+ color: white;
100
+ font-size: 24px;
101
+ border: none;
102
+ cursor: pointer;
103
+ }
104
+ .status, .response {
105
+ margin-top: 20px;
106
+ }
107
+ </style>
108
+ </head>
109
+ <body>
110
+ <h1>AI Dining Assistant</h1>
111
+ <button class="mic-button" id="mic-button">🎤</button>
112
+ <div class="status" id="status">Press the mic button to start...</div>
113
+ <div class="response" id="response" style="display: none;">Response will appear here...</div>
114
+ <script>
115
+ const micButton = document.getElementById('mic-button');
116
+ const status = document.getElementById('status');
117
+ const response = document.getElementById('response');
118
+ let isListening = false;
119
+ micButton.addEventListener('click', () => {
120
+ if (!isListening) {
121
+ isListening = true;
122
+ greetUser();
123
+ }
124
+ });
125
+ // Greeting the user and asking for their name
126
+ function greetUser() {
127
+ const utterance = new SpeechSynthesisUtterance("Hi, welcome to Biryani Hub! Can I know your name so I can greet you personally?");
128
+ speechSynthesis.speak(utterance);
129
+ utterance.onend = () => {
130
+ status.textContent = "Listening for your name...";
131
+ startListening();
132
+ };
133
+ }
134
+ // Start listening for the user's response
135
+ async function startListening() {
136
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
137
+ const mediaRecorder = new MediaRecorder(stream, { mimeType: "audio/webm;codecs=opus" });
138
+ const audioChunks = [];
139
+ mediaRecorder.ondataavailable = (event) => audioChunks.push(event.data);
140
+ mediaRecorder.onstop = async () => {
141
+ const audioBlob = new Blob(audioChunks, { type: "audio/webm" });
142
+ const formData = new FormData();
143
+ formData.append("audio", audioBlob);
144
+ status.textContent = "Processing your preference... Please wait.";
145
+ try {
146
+ const result = await fetch("/process-audio", { method: "POST", body: formData });
147
+ const data = await result.json();
148
+ response.textContent = data.response;
149
+ response.style.display = "block";
150
+ const utterance = new SpeechSynthesisUtterance(data.response);
151
+ speechSynthesis.speak(utterance);
152
+ utterance.onend = () => {
153
+ if (!data.response.includes("Goodbye") && !data.response.includes("final order")) {
154
+ startListening(); // Continue listening
155
+ } else {
156
+ status.textContent = "Conversation ended.";
157
+ isListening = false;
158
+ }
159
+ };
160
+ } catch (error) {
161
+ response.textContent = "Sorry, I couldn’t understand that. Could you please repeat?";
162
+ status.textContent = "Press the mic button to restart.";
163
+ isListening = false;
164
+ }
165
+ };
166
+ mediaRecorder.start();
167
+ setTimeout(() => mediaRecorder.stop(), 5000); // Stop recording after 5 seconds
168
+ }
169
+ </script>
170
+ </body>
171
+ </html>
172
+ """
173
+
174
+ @app.route("/")
175
+ def index():
176
+ return render_template_string(html_code)
177
+
178
+ @app.route("/process-audio", methods=["POST"])
179
  def process_audio():
180
+ global awaiting_preference, current_category, awaiting_quantity, cart, awaiting_item_selection, user_name
181
  try:
182
+ audio_file = request.files.get("audio")
183
+ if not audio_file:
184
+ raise BadRequest("No audio file provided.")
 
185
 
186
+ temp_file = NamedTemporaryFile(delete=False, suffix=".webm")
187
+ audio_file.save(temp_file.name)
188
 
189
+ if os.path.getsize(temp_file.name) == 0:
190
+ raise BadRequest("Uploaded audio file is empty.")
191
 
192
+ converted_file = NamedTemporaryFile(delete=False, suffix=".wav")
193
+ ffmpeg.input(temp_file.name).output(
194
+ converted_file.name, acodec="pcm_s16le", ac=1, ar="16000", loglevel='error'
195
+ ).run(overwrite_output=True)
196
 
197
+ recognizer = sr.Recognizer()
198
+ with sr.AudioFile(converted_file.name) as source:
199
+ recognizer.adjust_for_ambient_noise(source, duration=1) # Adjust for ambient noise
200
+ audio_data = recognizer.record(source, duration=10) # Increase the duration
201
+ try:
202
+ command = recognizer.recognize_google(audio_data)
203
+ logging.info(f"Recognized command: {command}") # Log the recognized command
204
+ response = process_command(command)
205
+ except sr.UnknownValueError:
206
+ response = "Sorry, I couldn't understand your command. Could you please repeat?"
207
+ except sr.RequestError as e:
208
+ response = f"Error with the speech recognition service: {e}"
209
 
210
+ return jsonify({"response": response})
211
+
212
+ except BadRequest as br:
213
+ return jsonify({"response": f"Bad Request: {str(br)}"}), 400
 
214
  except Exception as e:
215
+ return jsonify({"response": f"An error occurred: {str(e)}"}), 500
216
+ finally:
217
+ os.unlink(temp_file.name)
218
+ os.unlink(converted_file.name)
219
+
220
+ # Updated Email Handling
221
+ def process_command(command):
222
+ global awaiting_preference, current_category, awaiting_quantity, cart, awaiting_item_selection, user_email, user_name
223
+
224
+ logging.info(f"Processing command: {command}")
225
+
226
+ try:
227
+ # Step 1: Handle user name input (personalize the greeting)
228
+ if user_name is None and "my name is" in command:
229
+ user_name = command.replace("my name is", "").strip()
230
+ return jsonify({"response": f"Hello {user_name}! Nice to meet you. Please choose your preference: Veg, Non-Veg, or All."})
231
+
232
+ # Step 2: Handle preference (Veg/Non-Veg/All)
233
+ if awaiting_preference:
234
+ if "veg" in command:
235
+ current_category = 'Veg'
236
+ elif "non-veg" in command:
237
+ current_category = 'Non-Veg'
238
+ elif "all" in command:
239
+ current_category = 'All'
240
+ else:
241
+ return jsonify({"response": "I didn't catch your preference. Please choose Veg, Non-Veg, or All."})
242
+
243
+ awaiting_preference = False
244
+ awaiting_item_selection = True # Now ready for item selection
245
+ return jsonify({"response": f"Great! You've selected {current_category}. What would you like to order?"})
246
+
247
+ # Step 3: Handle item selection
248
+ if awaiting_item_selection:
249
+ menu_items = get_menu_items(current_category) # Simulate fetching menu items
250
+ selected_item = next((item for item in menu_items if item['Name'].lower() in command), None)
251
+
252
+ if selected_item:
253
+ cart.append({"Name": selected_item['Name'], "Price__c": selected_item['Price__c'], "Quantity": 0})
254
+ awaiting_item_selection = False
255
+ awaiting_quantity = True
256
+ return jsonify({"response": f"You selected {selected_item['Name']}. How many would you like to order?"})
257
+
258
+ return jsonify({"response": "I didn't catch that. Please say the name of the item you want to order."})
259
+
260
+ # Step 4: Handle quantity selection
261
+ if awaiting_quantity:
262
+ try:
263
+ quantity = int(command)
264
+ if quantity > 0:
265
+ cart[-1]["Quantity"] = quantity
266
+ awaiting_quantity = False
267
+ return jsonify({"response": f"Quantity set to {quantity}. Please provide your email to complete the order."})
268
+ else:
269
+ return jsonify({"response": "Quantity must be greater than zero."})
270
+ except ValueError:
271
+ return jsonify({"response": "Please provide a valid number for quantity."})
272
+
273
+ # Step 5: Handle email input
274
+ if "my email is" in command:
275
+ email_part = command.replace("my email is", "").strip()
276
+ email_command = email_part.replace(' at ', '@').replace(' dot ', '.').replace(' ', '')
277
+ logging.info(f"Processed email command: {email_command}")
278
+
279
+ email_pattern = r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$"
280
+ match = re.match(email_pattern, email_command)
281
+
282
+ if match:
283
+ user_email = match.group(0)
284
+ return jsonify({"response": f"Got it! Your email is {user_email}. Now, your order will be processed. Would you like to confirm your order?"})
285
+ else:
286
+ return jsonify({"response": "Sorry, that doesn't look like a valid email. Can you please provide it again?"})
287
+
288
+ # Step 6: Handle order finalization commands
289
+ if "final order" in command or "confirm my order" in command or "place the order" in command or "confirm order" in command:
290
+ return place_order()
291
+
292
+ return jsonify({"response": "I'm not sure what you're trying to do. Can you please repeat?"})
293
+
294
+ except Exception as e:
295
+ logging.error(f"An error occurred while processing the command: {str(e)}")
296
+ logging.error(f"Stack Trace: {traceback.format_exc()}") # Log full error details
297
+ return jsonify({"response": "Sorry, there was an error processing your request."}), 500
298
+
299
+ # Function to place the order
300
+ def place_order():
301
+ global cart, user_email, user_name
302
+
303
+ try:
304
+ # Calculate the total amount for the order
305
+ total_amount = sum([item['Price__c'] * item['Quantity'] for item in cart])
306
+
307
+ # Step 1: Save the main order record to Salesforce
308
+ order_record = save_order_to_salesforce(cart, user_email, total_amount)
309
+
310
+ # Step 2: Query Salesforce for the order just placed using the user's email and name
311
+ order_query = f"""
312
+ SELECT Id, Name, Customer_Email__c
313
+ FROM Order__c
314
+ WHERE Customer_Email__c = '{user_email}' AND Name = '{user_name}'
315
+ ORDER BY CreatedDate DESC LIMIT 1
316
+ """
317
+ order_result = sf.query_all(order_query)
318
+
319
+ # Ensure the order was created successfully
320
+ if not order_result['records']:
321
+ return jsonify({"response": "Failed to retrieve the placed order. Please try again."})
322
+
323
+ order_id = order_result['records'][0]['Id']
324
+
325
+ # Step 3: Add the food items as related records to the Order__c
326
+ for item in cart:
327
+ order_item = {
328
+ 'Order__c': order_id, # Link the item to the specific order
329
+ 'Item_Name__c': item['Name'], # Item name
330
+ 'Quantity__c': item['Quantity'], # Item quantity
331
+ 'Price__c': item['Price__c'], # Item price
332
+ }
333
+ sf.Order_Item__c.create(order_item) # Assuming you have a custom Order_Item__c object for items
334
+
335
+ # Step 4: Clear the cart after placing the order
336
+ cart = [] # Clear the cart
337
+
338
+ # Return the success message
339
+ return jsonify({"response": f"Order placed successfully! Total amount: ₹{total_amount}"})
340
+
341
+ except Exception as e:
342
+ return jsonify({"response": f"An error occurred: {str(e)}"}), 500
343
+
344
+
345
  if __name__ == "__main__":
346
+ app.run(host="0.0.0.0", port=7860)