File size: 13,444 Bytes
e71240e
 
 
 
 
 
 
 
 
 
 
 
408a4d8
 
e71240e
cce0f39
e71240e
 
 
 
 
 
 
 
f73965a
e71240e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fa7b884
 
 
 
 
 
 
 
e71240e
 
 
fa7b884
e71240e
 
 
 
 
 
 
fa7b884
e71240e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fa7b884
e71240e
 
 
 
 
 
 
 
fa7b884
e71240e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fa7b884
e71240e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
408a4d8
e71240e
408a4d8
e71240e
 
 
cce0f39
e71240e
 
de42bf3
e71240e
 
30e1c24
e71240e
 
 
 
30e1c24
e71240e
 
fa7b884
 
e71240e
 
fa7b884
e71240e
 
 
 
 
cce0f39
e71240e
 
 
 
408a4d8
e71240e
 
 
 
 
 
47c0034
e71240e
 
dddcc4b
e71240e
 
dddcc4b
e71240e
 
dddcc4b
 
 
 
 
 
e71240e
 
 
 
 
 
 
 
 
 
 
 
fa7b884
e71240e
 
 
fa7b884
e71240e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fa7b884
e71240e
 
 
 
 
 
 
 
fa7b884
e71240e
 
 
 
 
 
 
fa7b884
e71240e
 
fa7b884
e71240e
fa7b884
e71240e
 
fa7b884
 
 
 
e71240e
fa7b884
e71240e
 
 
 
 
 
 
 
408a4d8
fa7b884
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
from flask import Flask, render_template_string, request, jsonify
from simple_salesforce import Salesforce
import logging
from tempfile import NamedTemporaryFile
import os
import re
import traceback
import ffmpeg
import speech_recognition as sr
from werkzeug.exceptions import BadRequest
from datetime import datetime
from word2number import w2n  # Import word-to-number conversion library

app = Flask(__name__)
logging.basicConfig(level=logging.INFO)

# Salesforce connection setup
sf = Salesforce(
    username='diggavalli98@gmail.com',
    password='Sati@1020',
    security_token='sSSjyhInIsUohKpG8sHzty2q',
    consumer_key='3MVG9WVXk15qiz1JbtW1tT9a7Wnkos2RuGamw6p1lC5uPescT5NB2nPygpo6rQ87K1T.zBEn.wR.A6JdgHnIU',
    consumer_secret='A75C6B7801D5D20BED0E46631CF58C4F7FF28E4DAF442FE667553D29C35C0451'
)

# Global variables
cart = []  # To store items, quantities, prices, and add-ons
current_category = None
awaiting_preference = True
awaiting_quantity = False
user_email = None  # Will be set later once the user provides it
awaiting_item_selection = False  # Flag to know when to ask for item selection
user_name = None  # Will be set once the user provides their name

# Function to fetch menu items from Salesforce based on the category filter
def get_menu_items(category):
    category_filter = ''
    
    if category == 'Veg':
        category_filter = 'Veg'
    elif category == 'Non-Veg':
        category_filter = 'Non veg'
    elif category == 'All':
        category_filter = ''  # No filter for 'All'

    query = f"""
        SELECT Id, Name, Price__c, Image1__c, Veg_NonVeg__c, Section__c 
        FROM Menu_Item__c 
        WHERE Veg_NonVeg__c = '{category_filter}' OR Veg_NonVeg__c = 'both' 
        """ if category_filter else """
        SELECT Id, Name, Price__c, Image1__c, Veg_NonVeg__c, Section__c 
        FROM Menu_Item__c
    """
    result = sf.query_all(query)
    return result['records']

# Function to save order to Salesforce
def save_order_to_salesforce(cart, user_email, total_amount):
    order_items = ", ".join([f"{item['Name']} x {item['Quantity']}" for item in cart])
    order = {
        'Customer_Email__c': user_email,
        'Order_Date_Time__c': datetime.now(),
        'Order_Items__c': order_items,
        'Total_Amount__c': total_amount,
        'Status__c': 'Pending'
    }
    
    order_record = sf.Order__c.create(order)
    return order_record

# HTML Template for Frontend
html_code = """
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>AI Dining Assistant</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            text-align: center;
            background-color: #f4f4f9;
        }
        h1 {
            color: #333;
        }
        .mic-button {
            width: 80px;
            height: 80px;
            border-radius: 50%;
            background-color: #007bff;
            color: white;
            font-size: 24px;
            border: none;
            cursor: pointer;
        }
        .status, .response {
            margin-top: 20px;
        }
    </style>
</head>
<body>
    <h1>AI Dining Assistant</h1>
    <button class="mic-button" id="mic-button">🎤</button>
    <div class="status" id="status">Press the mic button to start...</div>
    <div class="response" id="response" style="display: none;">Response will appear here...</div>
    <script>
        const micButton = document.getElementById('mic-button');
        const status = document.getElementById('status');
        const response = document.getElementById('response');
        let isListening = false;
        micButton.addEventListener('click', () => {
            if (!isListening) {
                isListening = true;
                greetUser();
            }
        });

        function greetUser() {
            const utterance = new SpeechSynthesisUtterance("Hi, welcome to Biryani Hub! Can I know your name so I can greet you personally?");
            speechSynthesis.speak(utterance);
            utterance.onend = () => {
                status.textContent = "Listening for your name...";
                startListening();
            };
        }

        async function startListening() {
            const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
            const mediaRecorder = new MediaRecorder(stream, { mimeType: "audio/webm;codecs=opus" });
            const audioChunks = [];
            mediaRecorder.ondataavailable = (event) => audioChunks.push(event.data);
            mediaRecorder.onstop = async () => {
                const audioBlob = new Blob(audioChunks, { type: "audio/webm" });
                const formData = new FormData();
                formData.append("audio", audioBlob);
                status.textContent = "Processing your preference... Please wait.";
                try {
                    const result = await fetch("/process-audio", { method: "POST", body: formData });
                    const data = await result.json();
                    response.textContent = data.response;
                    response.style.display = "block";
                    const utterance = new SpeechSynthesisUtterance(data.response);
                    speechSynthesis.speak(utterance);
                    utterance.onend = () => {
                        if (!data.response.includes("Goodbye") && !data.response.includes("final order")) {
                            startListening();
                        } else {
                            status.textContent = "Conversation ended.";
                            isListening = false;
                        }
                    };
                } catch (error) {
                    response.textContent = "Sorry, I couldn’t understand that. Could you please repeat?";
                    status.textContent = "Press the mic button to restart.";
                    isListening = false;
                }
            };
            mediaRecorder.start();
            setTimeout(() => mediaRecorder.stop(), 5000); // Stop recording after 5 seconds
        }
    </script>
</body>
</html>
"""

@app.route("/")
def index():
    return render_template_string(html_code)

@app.route("/process-audio", methods=["POST"])
def process_audio():
    global awaiting_preference, current_category, awaiting_quantity, cart, awaiting_item_selection, user_name
    try:
        audio_file = request.files.get("audio")
        if not audio_file:
            raise BadRequest("No audio file provided.")

        temp_file = NamedTemporaryFile(delete=False, suffix=".webm")
        audio_file.save(temp_file.name)

        if os.path.getsize(temp_file.name) == 0:
            raise BadRequest("Uploaded audio file is empty.")

        converted_file = NamedTemporaryFile(delete=False, suffix=".wav")
        ffmpeg.input(temp_file.name).output(
            converted_file.name, acodec="pcm_s16le", ac=1, ar="16000", loglevel='error'
        ).run(overwrite_output=True)

        recognizer = sr.Recognizer()
        with sr.AudioFile(converted_file.name) as source:
            recognizer.adjust_for_ambient_noise(source, duration=1)  
            audio_data = recognizer.record(source, duration=10)  
            try:
                command = recognizer.recognize_google(audio_data)
                logging.info(f"Recognized command: {command}")
                response = process_command(command)
            except sr.UnknownValueError:
                response = "Sorry, I couldn't understand your command. Could you please repeat?"
            except sr.RequestError as e:
                response = f"Error with the speech recognition service: {e}"

        return jsonify({"response": response})

    except BadRequest as br:
        return jsonify({"response": f"Bad Request: {str(br)}"}), 400
    except Exception as e:
        return jsonify({"response": f"An error occurred: {str(e)}"}), 500
    finally:
        os.unlink(temp_file.name)
        os.unlink(converted_file.name)

# Updated Email Handling
def process_command(command):
    global awaiting_preference, current_category, awaiting_quantity, cart, awaiting_item_selection, user_email, user_name

    logging.info(f"Processing command: {command}")  # Indentation fixed

    try:
        # Step 1: Handle user name input (personalize the greeting)
        if user_name is None and "my name is" in command:
            user_name = command.replace("my name is", "").strip()
            return jsonify({"response": f"Hello {user_name}! Nice to meet you. Please choose your preference: Veg, Non-Veg, or All."})

        # Additional logic continues...
    except Exception as e:
        logging.error(f"An error occurred while processing the command: {str(e)}")
        return jsonify({"response": "Sorry, there was an error processing your request."}), 500

        if awaiting_preference:
            if "veg" in command:
                current_category = 'Veg'
            elif "non-veg" in command:
                current_category = 'Non-Veg'
            elif "all" in command:
                current_category = 'All'
            else:
                return jsonify({"response": "I didn't catch your preference. Please choose Veg, Non-Veg, or All."})
            
            awaiting_preference = False
            awaiting_item_selection = True  
            return jsonify({"response": f"Great! You've selected {current_category}. What would you like to order?"})

        if awaiting_item_selection:
            menu_items = get_menu_items(current_category)
            selected_item = next((item for item in menu_items if item['Name'].lower() in command), None)

            if selected_item:
                cart.append({"Name": selected_item['Name'], "Price__c": selected_item['Price__c'], "Quantity": 0})
                awaiting_item_selection = False
                awaiting_quantity = True
                return jsonify({"response": f"You selected {selected_item['Name']}. How many would you like to order?"})

            return jsonify({"response": "I didn't catch that. Please say the name of the item you want to order."})

        if awaiting_quantity:
            try:
                quantity = int(command)
                if quantity > 0:
                    cart[-1]["Quantity"] = quantity
                    awaiting_quantity = False
                    return jsonify({"response": f"Quantity set to {quantity}. Please provide your email to complete the order."})
                else:
                    return jsonify({"response": "Quantity must be greater than zero."})
            except ValueError:
                return jsonify({"response": "Please provide a valid number for quantity."})

        if "my email is" in command:
            email_part = command.replace("my email is", "").strip()
            email_command = email_part.replace(' at ', '@').replace(' dot ', '.').replace(' ', '')
            logging.info(f"Processed email command: {email_command}")

            email_pattern = r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$"
            match = re.match(email_pattern, email_command)

            if match:
                user_email = match.group(0)
                return jsonify({"response": f"Got it! Your email is {user_email}. Now, your order will be processed. Would you like to confirm your order?"})
            else:
                return jsonify({"response": "Sorry, that doesn't look like a valid email. Can you please provide it again?"})

        if "final order" in command or "confirm my order" in command or "place the order" in command or "confirm order" in command:
            return place_order()

        return jsonify({"response": "I'm not sure what you're trying to do. Can you please repeat?"})

    except Exception as e:
        logging.error(f"An error occurred while processing the command: {str(e)}")
        logging.error(f"Stack Trace: {traceback.format_exc()}")
        return jsonify({"response": "Sorry, there was an error processing your request."}), 500

def place_order():
    global cart, user_email, user_name
    
    try:
        total_amount = sum([item['Price__c'] * item['Quantity'] for item in cart])
        order_record = save_order_to_salesforce(cart, user_email, total_amount)

        order_query = f"""
            SELECT Id, Name, Customer_Email__c
            FROM Order__c
            WHERE Customer_Email__c = '{user_email}' AND Name = '{user_name}' 
            ORDER BY CreatedDate DESC LIMIT 1
        """
        order_result = sf.query_all(order_query)

        if not order_result['records']:
            return jsonify({"response": "Failed to retrieve the placed order. Please try again."})

        order_id = order_result['records'][0]['Id']

        for item in cart:
            order_item = {
                'Order__c': order_id,
                'Item_Name__c': item['Name'],
                'Quantity__c': item['Quantity'],
                'Price__c': item['Price__c'],
            }
            sf.Order_Item__c.create(order_item)

        cart = []  # Clear the cart
        return jsonify({"response": f"Order placed successfully! Total amount: ₹{total_amount}"})
    
    except Exception as e:
        return jsonify({"response": f"An error occurred: {str(e)}"}), 500


if __name__ == "__main__":
    app.run(host="0.0.0.0", port=7860)