lokesh341's picture
Update app.py
f39babe verified
raw
history blame
16.2 kB
from flask import Flask, render_template, request, jsonify
from simple_salesforce import Salesforce
from dotenv import load_dotenv
import os
import logging
import uuid
from datetime import datetime
# Load environment variables
load_dotenv()
# Set up logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
app = Flask(__name__, template_folder='templates', static_folder='static')
# Salesforce connection function
def get_salesforce_connection():
try:
sf = Salesforce(
username=os.getenv('SFDC_USERNAME'),
password=os.getenv('SFDC_PASSWORD'),
security_token=os.getenv('SFDC_SECURITY_TOKEN'),
domain=os.getenv('SFDC_DOMAIN', 'login')
)
logger.info("Successfully connected to Salesforce")
return sf
except Exception as e:
logger.error(f"Error connecting to Salesforce: {e}")
return None
# Initialize Salesforce connection
sf = get_salesforce_connection()
# Initialize OpenAI client
openai_api_key = os.getenv('OPENAI_API_KEY')
if not openai_api_key:
logger.error("OPENAI_API_KEY not found in .env. ChatGPT functionality disabled.")
client = None
else:
try:
client = OpenAI(api_key=openai_api_key)
test_response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": "Test API key"}]
)
logger.info("OpenAI API key validated successfully")
except Exception as e:
logger.error(f"Invalid OpenAI API key or connection issue: {e}")
client = None
# Conversation storage
conversation_sessions = {}
def is_restaurant_related(query):
keywords = ['use', 'uses', 'dish', 'recipe', 'ingredient', 'food', 'menu', 'vegetarian', 'non-vegetarian',
'rice', 'chicken', 'pasta', 'veggie', 'mutton', 'lamb', 'beef', 'pork', 'fish', 'seafood',
'ingredients', 'nutrition', 'nutritional', 'info', 'message', 'messages']
return bool(query.strip() and any(keyword in query.lower() for keyword in keywords)) or any(item in query.lower() for item in ['mutton', 'rice', 'chicken'])
def get_chatgpt_response(prompt, session_id):
if not client:
logger.warning("No OpenAI client available, using mock ChatGPT response")
if any(item in prompt.lower() for item in ['mutton', 'rice', 'chicken']):
return f"{prompt.capitalize()} is great for curries or roasts in a restaurant!"
return "I can help with food! Try 'uses of mutton' or 'ingredients for rice'."
if session_id not in conversation_sessions:
conversation_sessions[session_id] = [
{"role": "system", "content": "You are a restaurant culinary assistant. Respond only to queries about ingredients, dishes, or recipes. Provide concise, friendly answers. For unclear queries, suggest: 'Try 'uses of mutton' or 'ingredients for rice'.'"}
]
prompt = prompt.strip().lower()
logger.info(f"Processing prompt: {prompt}")
if not is_restaurant_related(prompt):
logger.info(f"Off-topic or empty query: {prompt}")
return "I can help with food! Try 'uses of mutton' or 'ingredients for rice'."
intent = "uses"
item = prompt
if "what is the use of" in prompt or "uses of" in prompt:
item = prompt.replace("what is the use of ", "").replace("uses of ", "").strip() or prompt
prompt = f"Provide the culinary uses of '{item}' for a restaurant. Be concise and friendly. If unknown, say 'Great for many dishes!'"
elif any(word in prompt for word in ['suggest', 'recipe', 'dish']):
intent = "suggest"
prompt = f"Suggest a restaurant dish based on: {prompt}. Include ingredients and be concise."
elif any(word in prompt for word in ['ingredients', 'ingredient']):
intent = "ingredients"
item = prompt.replace("ingredients for ", "").replace("ingredient of ", "").strip() or prompt
prompt = f"List common ingredients for a restaurant dish using '{item}'. Be concise and realistic."
elif any(word in prompt for word in ['nutrition', 'nutritional', 'info']):
intent = "nutrition"
item = prompt.replace("nutrition of ", "").replace("nutritional info for ", "").strip() or prompt
prompt = f"Provide a concise, approximate nutritional overview (calories, protein, fat, carbs) for a restaurant portion of '{item}'. Use general culinary knowledge and keep it friendly."
elif any(item in prompt for item in ['mutton', 'rice', 'chicken', 'pasta', 'veggie', 'lamb', 'beef', 'pork', 'fish', 'seafood']):
prompt = f"Provide the culinary uses of '{item}' for a restaurant. Be concise and friendly. If unknown, say 'Great for many dishes!'"
else:
logger.info(f"Unclear intent, defaulting to uses for: {prompt}")
prompt = f"Provide the culinary uses of '{prompt}' for a restaurant. Be concise and friendly. If unknown, say 'Great for many dishes!'"
conversation_sessions[session_id].append({"role": "user", "content": prompt})
try:
response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=conversation_sessions[session_id],
max_tokens=150,
timeout=10
)
reply = response.choices[0].message.content.strip()
conversation_sessions[session_id].append({"role": "assistant", "content": reply})
logger.info(f"ChatGPT response for '{prompt}': {reply}")
return reply
except Exception as e:
logger.error(f"OpenAI API error: {e}")
return f"Sorry, API failed. Mock response: {prompt.capitalize()} is great for curries or roasts!"
@app.route('/')
def index():
return render_template('index.html')
@app.route('/get_menu_items', methods=['POST'])
def get_menu_items():
global sf
if not sf:
sf = get_salesforce_connection()
if not sf:
return jsonify({"error": "Unable to connect to Salesforce"}), 500
data = request.json
dietary_preference = data.get('dietary_preference', 'both').lower()
search_term = data.get('search_term', '').strip()
try:
items = []
if not search_term:
soql = "SELECT Name, Image_URL__c, Category__c, Description__c FROM Sector_Detail__c"
if dietary_preference == 'vegetarian':
soql += " WHERE Category__c = 'Veg'"
elif dietary_preference == 'non-vegetarian':
soql += " WHERE Category__c = 'Non-Veg'"
soql += " LIMIT 200"
result = sf.query(soql)
items = [
{
"name": r['Name'],
"image_url": r.get('Image_URL__c', ''),
"category": r.get('Category__c', ''),
"description": r.get('Description__c', 'No description'),
"source": "Sector_Detail__c"
}
for r in result['records'] if 'Name' in r
]
else:
soql_menu = "SELECT Name, Description__c, Image1__c, Ingredientsinfo__c, NutritionalInfo__c, Price__c, Sector__c, Spice_Levels__c, Veg_NonVeg__c, Category__c, Dynamic_Dish__c FROM Menu_Item__c"
soql_menu += f" WHERE Name LIKE '%{search_term}%' OR Ingredientsinfo__c LIKE '%{search_term}%'"
if dietary_preference == 'vegetarian':
soql_menu += " AND Veg_NonVeg__c = 'Vegetarian'"
elif dietary_preference == 'non-vegetarian':
soql_menu += " AND Veg_NonVeg__c = 'Non-Vegetarian'"
soql_menu += " LIMIT 200"
logger.info(f"Executing SOQL query for Menu_Item__c: {soql_menu}")
result_menu = sf.query(soql_menu)
menu_items = [
{
"name": record['Name'],
"description": record.get('Description__c', 'No description available'),
"image_url": record.get('Image1__c', ''),
"ingredients": record.get('Ingredientsinfo__c', ''),
"nutritional_info": record.get('NutritionalInfo__c', ''),
"price": record.get('Price__c', 0.0),
"sector": record.get('Sector__c', ''),
"spice_levels": record.get('Spice_Levels__c', ''),
"veg_nonveg": record.get('Veg_NonVeg__c', ''),
"category": record.get('Category__c', ''),
"dynamic_dish": record.get('Dynamic_Dish__c', False),
"source": "Menu_Item__c"
}
for record in result_menu['records'] if 'Name' in record
]
items.extend(menu_items)
return jsonify({"menu_items": items})
except Exception as e:
logger.error(f"Failed to fetch items: {e}")
return jsonify({"error": f"Failed to fetch items: {e}"}), 500
@app.route('/get_sector_item_details', methods=['POST'])
def get_sector_item_details():
global sf
if not sf:
sf = get_salesforce_connection()
if not sf:
return jsonify({"error": "Unable to connect to Salesforce"}), 500
item_name = request.json.get('item_name', '').strip()
if not item_name:
return jsonify({"error": "Item name is required"}), 400
try:
soql = f"SELECT Name, Image_URL__c, Category__c, Description__c FROM Sector_Detail__c WHERE Name LIKE '%{item_name}%' LIMIT 1"
logger.info(f"Executing SOQL query: {soql}")
result = sf.query(soql)
if result['totalSize'] == 0:
return jsonify({"error": f"No item found matching '{item_name}' in Sector_Detail__c"}), 404
record = result['records'][0]
item_details = {
"name": record.get('Name', ''),
"image_url": record.get('Image_URL__c', 'https://via.placeholder.com/30'),
"category": record.get('Category__c', ''),
"description": record.get('Description__c', 'No description available')
}
logger.info(f"Fetched details for '{item_name}' from Sector_Detail__c")
return jsonify({"item_details": item_details})
except Exception as e:
logger.error(f"Failed to fetch item details from Sector_Detail__c: {e}")
return jsonify({"error": f"Failed to fetch item details: {e}"}), 500
@app.route('/suggest_items', methods=['POST'])
def suggest_items():
global sf
if not sf:
sf = get_salesforce_connection()
if not sf:
return jsonify({"error": "Unable to connect to Salesforce"}), 500
search_term = request.json.get('search_term', '').strip()
if not search_term:
return jsonify({"error": "Search term is required"}), 400
try:
soql = f"SELECT Ingredient_Name__c, Image_URL__c FROM Ingredient_Object__c WHERE Ingredient_Name__c LIKE '%{search_term}%' LIMIT 10"
logger.info(f"Executing SOQL query: {soql}")
result = sf.query(soql)
suggestions = [
{"name": record['Ingredient_Name__c'], "image_url": record.get('Image_URL__c', '')}
for record in result['records'] if 'Ingredient_Name__c' in record
]
logger.info(f"Fetched {len(suggestions)} suggestions for '{search_term}'")
return jsonify({"suggestions": suggestions})
except Exception as e:
logger.error(f"Failed to fetch suggestions: {e}")
return jsonify({"error": f"Failed to fetch suggestions: {e}"}), 500
@app.route('/get_item_details', methods=['POST'])
def get_item_details():
global sf
if not sf:
sf = get_salesforce_connection()
if not sf:
return jsonify({"error": "Unable to connect to Salesforce"}), 500
item_name = request.json.get('item_name', '').strip()
if not item_name:
return jsonify({"error": "Item name is required"}), 400
try:
soql = f"SELECT Ingredient_Name__c, Image_URL__c FROM Ingredient_Object__c WHERE Ingredient_Name__c LIKE '%{item_name}%' LIMIT 1"
logger.info(f"Executing SOQL query: {soql}")
result = sf.query(soql)
if result['totalSize'] == 0:
return jsonify({"error": f"No item found matching '{item_name}' in Ingredient_Object__c"}), 404
record = result['records'][0]
item_details = {
"name": record.get('Ingredient_Name__c', ''),
"image_url": record.get('Image_URL__c', '')
}
logger.info(f"Fetched details for '{item_name}'")
return jsonify({"item_details": item_details})
except Exception as e:
logger.error(f"Failed to fetch item details: {e}")
return jsonify({"error": f"Failed to fetch item details: {e}"}), 500
@app.route('/submit_items', methods=['POST'])
def submit_items():
global sf
if not sf:
sf = get_salesforce_connection()
if not sf:
return jsonify({"error": "Unable to connect to Salesforce"}), 500
items = request.json.get('items', [])
custom_order_name = request.json.get('custom_order_name', '')
if not items:
return jsonify({"error": "No items to submit"}), 400
try:
ingredient_name = custom_order_name or f"Order_{datetime.now().strftime('%Y%m%d')}_{uuid.uuid4().hex[:8]}"
item_names = ', '.join(item['name'] for item in items)
description = f"Contains: {item_names}"
for item in items:
sf.Ingredient_Object__c.create({
'Ingredient_Name__c': ingredient_name,
'Category__c': item.get('category', ''),
'Description__c': f"{item.get('description', 'No description')} - {description}",
'Image_URL__c': item.get('image_url', ''),
'Quantity__c': item.get('quantity', 1)
})
return jsonify({"success": f"Submitted {len(items)} items under {ingredient_name}", "ingredient_name": ingredient_name})
except Exception as e:
logger.error(f"Failed to submit items: {e}")
return jsonify({"error": f"Failed to submit items: {e}"}), 500
@app.route('/get_item_info', methods=['POST'])
def get_item_info():
global sf, client
item_name = request.json.get('item_name', '').strip()
if not item_name or not client:
return jsonify({"error": "Item name required or OpenAI unavailable"}), 400
try:
soql = f"SELECT Name, Description__c FROM Sector_Detail__c WHERE Name LIKE '%{item_name}%' LIMIT 1"
result = sf.query(soql)
if result['totalSize'] == 0:
return jsonify({"error": f"No item found matching '{item_name}'"}), 404
record = result['records'][0]
base_info = record.get('Description__c', 'No description available')
prompt = f"Based on general culinary knowledge, provide a concise list of common ingredients and an approximate nutritional overview (calories, protein, fat, carbs) for a restaurant portion of '{item_name}'. Use realistic values and keep it friendly."
response = client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[{"role": "user", "content": prompt}],
max_tokens=150,
timeout=10
)
ai_response = response.choices[0].message.content.strip()
item_info = {
"name": record['Name'],
"description": base_info,
"details": ai_response
}
logger.info(f"Generated info for '{item_name}'")
return jsonify({"item_info": item_info})
except Exception as e:
logger.error(f"Failed to get item info: {e}")
return jsonify({"error": f"Failed to get item info: {e}"}), 500
@app.route('/chat', methods=['POST'])
def chat():
user_message = request.json.get('message', '').strip()
session_id = request.json.get('session_id', 'default')
if not user_message:
return jsonify({"error": "No message provided"}), 400
response = get_chatgpt_response(user_message, session_id)
logger.info(f"Chat response sent: {response}")
return jsonify({"response": response, "search_term": user_message})
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=7860)