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 = """
AI Dining Assistant
AI Dining Assistant
Press the mic button to start...
Response will appear here...
"""
@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)