File size: 10,367 Bytes
7f2bf77
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ec4772b
 
7f2bf77
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
dd6336d
7f2bf77
 
 
81a30b4
9089005
c800706
 
 
7f2bf77
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ec4772b
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
from flask import Flask, render_template_string, request, jsonify
import speech_recognition as sr
from tempfile import NamedTemporaryFile
import os
import ffmpeg
import logging
from werkzeug.exceptions import BadRequest

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

# Global variables
cart = []  # To store items, quantities, and prices
MENU = {
    "Biryanis": {"Chicken Biryani": 250, "Veg Biryani": 200, "Mutton Biryani": 300},
    "Starters": {"Chicken Wings": 220, "Paneer Tikka": 180, "Fish Fingers": 250, "Spring Rolls": 160},
    "Rotis": {"Butter Naan": 50, "Garlic Naan": 60, "Roti": 40, "Lachha Paratha": 70},
    "Main Course": {"Butter Chicken": 300, "Paneer Butter Masala": 250, "Dal Tadka": 200, "Chicken Tikka Masala": 320},
    "Drinks": {"Coke": 60, "Sprite": 60, "Mango Lassi": 80, "Masala Soda": 70},
    "Desserts": {"Gulab Jamun": 100, "Rasgulla": 90, "Ice Cream": 120, "Brownie with Ice Cream": 180},
}
current_category = None
current_item = None
awaiting_quantity = False

# Extract quantity from command (e.g., "two" -> 2, "three" -> 3, etc.)
def extract_quantity(command):
    number_words = {
        "one": 1, "two": 2, "three": 3, "four": 4, "five": 5,
        "six": 6, "seven": 7, "eight": 8, "nine": 9, "ten": 10,
        "1": 1, "2": 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7, "8": 8, "9": 9, "10": 10
    }
    
    command_words = command.split()
    for word in command_words:
        if word in number_words:
            return number_words[word]
    return None

# 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 show you the menu?");
            speechSynthesis.speak(utterance);
            utterance.onend = () => {
                status.textContent = "Listening...";
                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...";
                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(); // Continue listening
                        } else {
                            status.textContent = "Conversation ended.";
                            isListening = false;
                        }
                    };
                } catch (error) {
                    response.textContent = "Error processing your request. Please try again.";
                    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 current_category, current_item, awaiting_quantity
    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"
        ).run(overwrite_output=True)

        recognizer = sr.Recognizer()
        with sr.AudioFile(converted_file.name) as source:
            audio_data = recognizer.record(source)
            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)

def process_command(command):
    global cart, MENU, current_category, current_item, awaiting_quantity
    command = command.lower()

    # Handle quantity input
    if awaiting_quantity:
        quantity = extract_quantity(command)
        if quantity:
            cart.append((current_item, MENU[current_category][current_item], quantity))
            awaiting_quantity = False
            item = current_item
            current_item = None
            total = sum(i[1] * i[2] for i in cart)
            cart_summary = ", ".join([f"{i[0]} x{i[2]} (₹{i[1] * i[2]})" for i in cart])
            return f"Added {quantity} x {item} to your cart. Your current cart: {cart_summary}. Total: ₹{total}. Would you like to add more items?"
        else:
            return "Sorry, I couldn't understand the quantity. Please provide a valid quantity."

    # Handle category selection
    for category, items in MENU.items():
        if category.lower() in command:
            current_category = category
            item_list = ", ".join([f"{item} (₹{price})" for item, price in items.items()])
            return f"{category} menu: {item_list}. What would you like to order?"

    # Handle item selection with dynamic matching
    if current_category:
        for item in MENU[current_category].keys():
            if item.lower().startswith(command) or command in item.lower():
                current_item = item
                awaiting_quantity = True
                return f"How many quantities of {current_item} would you like?"

    # Handle item removal
    if "remove" in command:
        for item in cart:
            if item[0].lower() in command:
                cart.remove(item)
                total = sum(i[1] * i[2] for i in cart)
                cart_summary = ", ".join([f"{i[0]} x{i[2]} (₹{i[1] * i[2]})" for i in cart])
                return f"Removed {item[0]} from your cart. Updated cart: {cart_summary}. Total: ₹{total}."
        return "The item you are trying to remove is not in your cart."

    # Handle final order
    if "final order" in command or "submit" in command or "Proceed" in command or "place the order" in command:
        if cart:
            order_details = ", ".join([f"{item[0]} x{item[2]} (₹{item[1] * item[2]})" for item in cart])
            total = sum(item[1] * item[2] for item in cart)
            cart.clear()
            return f"Your final order is: {order_details}. Total price: ₹{total}. Your order will arrive soon, Thank you for visiting Biryani Hub!"
        else:
            return "Your cart is empty. Please add items before placing the final order."

    # Handle cart details
    if "cart details" in command:
        if cart:
            cart_summary = "\n".join([f"{i[0]} x{i[2]} (₹{i[1] * i[2]})" for i in cart])
            total = sum(i[1] * i[2] for i in cart)
            return f"Your cart contains:\n{cart_summary}\nTotal: ₹{total}."
        else:
            return "Your cart is empty."

    # Handle menu request
    if "menu" in command or "yes" in command or "yeah" in command:
        categories = ", ".join(MENU.keys())
        return f"We have the following categories: {categories}. Please select a category to proceed."

    # Default response
    return "Sorry, I didn't understand that. Please try again."


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