cindyy3's picture
Update app.py
64ce67e verified
import gradio as gr
from sentence_transformers import SentenceTransformer, util
import openai
import random
import os
os.environ["TOKENIZERS_PARALLELISM"] = "false"
openai.api_key = os.environ["OPENAI_API_KEY"]
# Initialize paths and model identifiers for easy configuration and maintenance
filename = "output_topic_details.txt" # Path to the file storing restaurant-specific details
retrieval_model_name = 'output/sentence-transformer-finetuned/'
# Initialize the system message for the chatbot
system_message = "You are a restaurant recommending chatbot that suggests ONLY ONE restaurant in Seattle from the restaurant database based on the criteria the user provides."
# Initial system message to set the behavior of the assistant
messages = [{"role": "system", "content": system_message}]
# Load the SentenceTransformer model
try:
retrieval_model = SentenceTransformer(retrieval_model_name)
print("Models loaded successfully.")
except Exception as e:
print(f"Failed to load models: {e}")
def load_and_preprocess_text(filename):
"""
Load and preprocess text from a file, removing empty lines and stripping whitespace.
"""
try:
with open(filename, 'r', encoding='utf-8') as file:
segments = [line.strip() for line in file if line.strip()]
print("Text loaded and preprocessed successfully.")
return segments
except Exception as e:
print(f"Failed to load or preprocess text: {e}")
return []
segments = load_and_preprocess_text(filename)
def find_relevant_segment(user_query, segments):
"""
Find the most relevant text segment for a user's query using cosine similarity among sentence embeddings.
This version finds the best match based on the content of the query.
"""
try:
lower_query = user_query.lower()
query_embedding = retrieval_model.encode(lower_query)
segment_embeddings = retrieval_model.encode(segments)
similarities = util.pytorch_cos_sim(query_embedding, segment_embeddings)[0]
best_idx = similarities.argmax()
return segments[best_idx]
except Exception as e:
print(f"Error in finding relevant segment: {e}")
return ""
def generate_response(user_query, relevant_segment):
"""
Generate a response emphasizing the bot's capability in suggesting a restaurant.
"""
try:
user_message = f"Here is a local restaurant based on your information: {relevant_segment}"
messages.append({"role": "user", "content": user_message})
response = openai.ChatCompletion.create(
model="gpt-4",
messages=messages,
max_tokens=150,
temperature=0.2,
top_p=1,
frequency_penalty=0,
presence_penalty=0
)
output_text = response['choices'][0]['message']['content'].strip()
messages.append({"role": "assistant", "content": output_text})
return output_text
except Exception as e:
print(f"Error in generating response: {e}")
return f"Error in generating response: {e}"
# Define a sample list of restaurants (replace this with your actual data source)
restaurants = [
{
"name": "Harvest Beat",
"price": "High",
"cuisine": "American",
"gluten_free": True,
"vegan": True,
"lactose_intolerant": True,
"pescatarian": True,
"allergen_friendly": True,
"halal": False,
"kosher": False,
"vegetarian": True,
"website": "https://www.harvestbeat.com/"
},
{
"name": "Plum Bistro",
"price": "Moderate",
"cuisine": "American",
"gluten_free": True,
"vegan": True,
"lactose_intolerant": True,
"pescatarian": True,
"allergen_friendly": True,
"halal": False,
"kosher": False,
"vegetarian": True,
"website": "https://plumbistro.com/"
},
{
"name": "Portage Bay Cafe",
"price": "Low",
"cuisine": "American",
"gluten_free": True,
"vegan": True,
"lactose_intolerant": True,
"pescatarian": True,
"allergen_friendly": False,
"halal": False,
"kosher": False,
"vegetarian": True,
"website": "https://www.portagebaycafe.com/"
},
{
"name": "Duke's Seafood",
"price": "High",
"cuisine": "American",
"gluten_free": True,
"vegan": False,
"lactose_intolerant": True,
"pescatarian": True,
"allergen_friendly": True,
"halal": False,
"kosher": False,
"vegetarian": False,
"website": "https://www.dukesseafood.com/"
},
{
"name": "Olmstead",
"price": "Moderate",
"cuisine": "American",
"gluten_free": False,
"vegan": False,
"lactose_intolerant": False,
"pescatarian": False,
"allergen_friendly": False,
"halal": False,
"kosher": False,
"vegetarian": False,
"website": "https://www.olmsteadseattle.com/home"
},
{
"name": "Veggie Grill",
"price": "Low",
"cuisine": "American",
"gluten_free": True,
"vegan": True,
"lactose_intolerant": True,
"pescatarian": True,
"allergen_friendly": True,
"halal": False,
"kosher": False,
"vegetarian": True,
"website": "https://www.veggiegrill.com/menus/"
},
{
"name": "Cafe Flora",
"price": "Moderate",
"cuisine": "American",
"gluten_free": False,
"vegan": True,
"lactose_intolerant": False,
"pescatarian": True,
"allergen_friendly": False,
"halal": False,
"kosher": False,
"vegetarian": True,
"website": "https://florarestaurantgroup.com/"
},
{
"name": "Bounty Kitchen",
"price": "Low",
"cuisine": "American",
"gluten_free": True,
"vegan": True,
"lactose_intolerant": False,
"pescatarian": True,
"allergen_friendly": True,
"halal": False,
"kosher": False,
"vegetarian": True,
"website": "http://www.bountykitchenseattle.com/"
},
{
"name": "No Bones Beach Club",
"price": "Low",
"cuisine": "American",
"gluten_free": True,
"vegan": True,
"lactose_intolerant": False,
"pescatarian": True,
"allergen_friendly": True,
"halal": False,
"kosher": False,
"vegetarian": True,
"website": "https://nobonesbeachclub.com/menu/"
},
{
"name": "Chiho Bistro",
"price": "Low",
"cuisine": "Chinese",
"gluten_free": False,
"vegan": True,
"lactose_intolerant": False,
"pescatarian": False,
"allergen_friendly": False,
"halal": False,
"kosher": False,
"vegetarian": False,
"website": "https://www.chihobistro.com/"
},
{
"name": "Uptown China",
"price": "Moderate",
"cuisine": "Chinese",
"gluten_free": False,
"vegan": True,
"lactose_intolerant": True,
"pescatarian": True,
"allergen_friendly": False,
"halal": False,
"kosher": False,
"vegetarian": True,
"website": "https://uptown-china.com/"
},
{
"name": "Meskel Ethiopian Restaurant",
"price": "Moderate",
"cuisine": "Ethiopian",
"gluten_free": True,
"vegan": True,
"lactose_intolerant": True,
"pescatarian": True,
"allergen_friendly": True,
"halal": False,
"kosher": False,
"vegetarian": True,
"website": "https://meskelethiopian.com/menu"
},
{
"name": "Habesha Cafe",
"price": "Moderate",
"cuisine": "Ethiopian",
"gluten_free": False,
"vegan": True,
"lactose_intolerant": False,
"pescatarian": True,
"allergen_friendly": False,
"halal": False,
"kosher": False,
"vegetarian": True,
"website": "https://habesha.cafe/"
},
{
"name": "Musang",
"price": "High",
"cuisine": "Filipino",
"gluten_free": True,
"vegan": False,
"lactose_intolerant": True,
"pescatarian": True,
"allergen_friendly": True,
"halal": False,
"kosher": False,
"vegetarian": False,
"website": "https://www.musangseattle.com/"
},
{
"name": "Musang Seattle",
"price": "Moderate",
"cuisine": "Filipino",
"gluten_free": True,
"vegan": True,
"lactose_intolerant": True,
"pescatarian": True,
"allergen_friendly": False,
"halal": False,
"kosher": False,
"vegetarian": True,
"website": "https://www.musangseattle.com/musang"
},
{
"name": "Gold Coast Ghal",
"price": "Moderate",
"cuisine": "Ghanaian",
"gluten_free": False,
"vegan": False,
"lactose_intolerant": False,
"pescatarian": False,
"allergen_friendly": False,
"halal": False,
"kosher": False,
"vegetarian": False,
"website": "https://www.goldcoastghal.com/"
},
{
"name": "Marination Ma Kai",
"price": "Low",
"cuisine": "Hawaiian-Korean",
"gluten_free": True,
"vegan": False,
"lactose_intolerant": True,
"pescatarian": True,
"allergen_friendly": True,
"halal": False,
"kosher": False,
"vegetarian": True,
"website": "https://marinationmobile.com/menu"
},
{
"name": "Pabla Indian Cuisine",
"price": "Low",
"cuisine": "Indian",
"gluten_free": True,
"vegan": True,
"lactose_intolerant": True,
"pescatarian": True,
"allergen_friendly": False,
"halal": True,
"kosher": False,
"vegetarian": True,
"website": "http://www.pablacuisine"
},
{
"name": "Mint Progressive Indian",
"price": "Moderate",
"cuisine": "Indian",
"gluten_free": True,
"vegan": True,
"lactose_intolerant": True,
"pescatarian": True,
"allergen_friendly": False,
"halal": False,
"kosher": False,
"vegetarian": True,
"website": "https://www.mintprogressive.com/"
},
{
"name": "Cantinetta",
"price": "Moderate",
"cuisine": "Italian",
"gluten_free": False,
"vegan": False,
"lactose_intolerant": False,
"pescatarian": False,
"allergen_friendly": False,
"halal": False,
"kosher": False,
"vegetarian": False,
"website": "https://www.cantinettausa.com/wallingfordYes"
},
{
"name": "The Pink Door",
"price": "High",
"cuisine": "Italian",
"gluten_free": True,
"vegan": True,
"lactose_intolerant": True,
"pescatarian": False,
"allergen_friendly": False,
"halal": False,
"kosher": False,
"vegetarian": True,
"website": "https://www.thepinkdoor.net/"
},
{
"name": "Mashiko",
"price": "High",
"cuisine": "Japanese",
"gluten_free": False,
"vegan": True,
"lactose_intolerant": True,
"pescatarian": True,
"allergen_friendly": False,
"halal": False,
"kosher": False,
"vegetarian": False,
"website": "https://www.mashikorestaurant.com/"
},
{
"name": "Ben's Fast Food",
"price": "Low",
"cuisine": "Mexican",
"gluten_free": True,
"vegan": True,
"lactose_intolerant": True,
"pescatarian": True,
"allergen_friendly": False,
"halal": False,
"kosher": False,
"vegetarian": True,
"website": "https://bensfastfood.com/"
},
{
"name": "Sal y Limon",
"price": "Moderate",
"cuisine": "Mexican",
"gluten_free": False,
"vegan": False,
"lactose_intolerant": False,
"pescatarian": False,
"allergen_friendly": False,
"halal": False,
"kosher": False,
"vegetarian": True,
"website": "https://www.salylimonseattle.com/"
},
{
"name": "El Borracho",
"price": "Low",
"cuisine": "Mexican",
"gluten_free": True,
"vegan": True,
"lactose_intolerant": True,
"pescatarian": True,
"allergen_friendly": False,
"halal": False,
"kosher": False,
"vegetarian": True,
"website": "https://www.elborracho.co/"
},
{
"name": "Tanoor",
"price": "Moderate",
"cuisine": "Middle Eastern",
"gluten_free": True,
"vegan": True,
"lactose_intolerant": True,
"pescatarian": True,
"allergen_friendly": True,
"halal": True,
"kosher": False,
"vegetarian": True,
"website": "https://www.tanoor.com/"
},
{
"name": "Mamnoon",
"price": "Moderate",
"cuisine": "Middle Eastern",
"gluten_free": True,
"vegan": True,
"lactose_intolerant": True,
"pescatarian": True,
"allergen_friendly": False,
"halal": False,
"kosher": False,
"vegetarian": True,
"website": "https://nadimama.com/mamnoon"
},
{
"name": "Gorgeous George's",
"price": "Moderate",
"cuisine": "Middle Eastern",
"gluten_free": True,
"vegan": True,
"lactose_intolerant": True,
"pescatarian": True,
"allergen_friendly": False,
"halal": False,
"kosher": False,
"vegetarian": True,
"website": "https://www.gorgeousgeorges.com/"
},
{
"name": "Zaina",
"price": "Low",
"cuisine": "Middle Eastern",
"gluten_free": True,
"vegan": True,
"lactose_intolerant": True,
"pescatarian": True,
"allergen_friendly": True,
"halal": True,
"kosher": False,
"vegetarian": True,
"website": "https://www.yelp.com/biz/zaina-food-drinks-and-friends-seattle-3"
},
{
"name": "Gold Schnitzel",
"price": "Moderate",
"cuisine": "Middle Eastern",
"gluten_free": False,
"vegan": False,
"lactose_intolerant": True,
"pescatarian": False,
"allergen_friendly": True,
"halal": False,
"kosher": False,
"vegetarian": False,
"website": "https://goldschnitzel.com/"
},
{
"name": "Maza Grill",
"price": "Moderate",
"cuisine": "Pakistani",
"gluten_free": False,
"vegan": False,
"lactose_intolerant": False,
"pescatarian": False,
"allergen_friendly": True,
"halal": False,
"kosher": False,
"vegetarian": False,
"website": "https://mazagrill.co/"
},
{
"name": "Terra Plata",
"price": "High",
"cuisine": "Spanish",
"gluten_free": False,
"vegan": False,
"lactose_intolerant": False,
"pescatarian": True,
"allergen_friendly": False,
"halal": False,
"kosher": False,
"vegetarian": False,
"website": "https://www.terraplata.com/"
},
{
"name": "Pestle Rock",
"price": "Moderate",
"cuisine": "Thai",
"gluten_free": True,
"vegan": True,
"lactose_intolerant": True,
"pescatarian": True,
"allergen_friendly": False,
"halal": False,
"kosher": False,
"vegetarian": True,
"website": "https://pestlerock.com/"
},
{
"name": "Araya's Place",
"price": "Low",
"cuisine": "Thai",
"gluten_free": False,
"vegan": True,
"lactose_intolerant": False,
"pescatarian": False,
"allergen_friendly": False,
"halal": False,
"kosher": False,
"vegetarian": True,
"website": "https://www.arayasplace.com/"
},
{
"name": "Cafe Turko",
"price": "Moderate",
"cuisine": "Turkish",
"gluten_free": True,
"vegan": True,
"lactose_intolerant": True,
"pescatarian": True,
"allergen_friendly": False,
"halal": True,
"kosher": False,
"vegetarian": True,
"website": "https://cafeturko.com/#"
},
{
"name": "Blossom Vegetarian",
"price": "Low",
"cuisine": "Vietnamese",
"gluten_free": True,
"vegan": True,
"lactose_intolerant": True,
"pescatarian": False,
"allergen_friendly": False,
"halal": False,
"kosher": False,
"vegetarian": True,
"website": "https://www.blossomrenton.com/"
},
{
"name": "Tilikum",
"price": "Moderate",
"cuisine": "European",
"gluten_free": False,
"vegan": False,
"lactose_intolerant": False,
"pescatarian": True,
"allergen_friendly": False,
"halal": False,
"kosher": False,
"vegetarian": False,
"website": "https://www.tilikumplacecafe.com/"
}
# Add more restaurant entries as needed
]
def find_restaurants(criteria):
"""
Finds restaurants based on the given criteria.
Parameters:
criteria (dict): Dictionary containing filtering criteria.
Returns:
List of restaurants that match the criteria.
"""
matching_restaurants = []
for restaurant in restaurants:
match = True
for key, value in criteria.items():
if key in restaurant:
if isinstance(restaurant[key], bool):
if restaurant[key] != value:
match = False
break
elif restaurant[key].lower() != value.lower():
match = False
break
if match:
matching_restaurants.append(restaurant)
return matching_restaurants
def generate_recommendation(criteria):
"""
Generates a recommendation based on the criteria.
Parameters:
criteria (dict): Dictionary containing filtering criteria.
Returns:
String with the recommendation or a message if no matches are found.
"""
results = find_restaurants(criteria)
if results:
recommendations = []
for result in results:
recommendation = (
f"Based on your criteria, I recommend {result['name']}. "
f"It's a {result['price'].lower()} priced {result['cuisine'].lower()} restaurant with "
f"{'gluten-free options' if result['gluten_free'] else 'no gluten-free options'}, "
f"{'vegan options' if result['vegan'] else 'no vegan options'}, "
f"{'lactose-intolerant options' if result['lactose_intolerant'] else 'no lactose-intolerant options'}, "
f"{'pescatarian options' if result['pescatarian'] else 'no pescatarian options'}, "
f"{'allergen-friendly options' if result['allergen_friendly'] else 'no allergen-friendly options'}, "
f"{'halal options' if result['halal'] else 'no halal options'}, "
f"{'kosher options' if result['kosher'] else 'no kosher options'}, "
f"and { 'vegetarian options' if result['vegetarian'] else 'no vegetarian options'}. "
f"Visit their website for more details: {result['website']}"
)
recommendations.append(recommendation)
random_index = random.randint(0, len(recommendations) - 1)
return recommendations[random_index]
else:
return "Sorry, no restaurants meet your criteria. Please try adjusting your filters."
def query_model(question):
"""
Process a question, find relevant information, and generate a response.
"""
if question == "":
return "Give me your preferences..."
if "restaurant" in question.lower():
# Extract criteria from the question
criteria = {}
if "gluten-free" in question.lower():
criteria["gluten_free"] = True
if "vegan" in question.lower():
criteria["vegan"] = True
if "lactose-intolerant" in question.lower():
criteria["lactose_intolerant"] = True
if "pescatarian" in question.lower():
criteria["pescatarian"] = True
if "allergen-friendly" in question.lower():
criteria["allergen_friendly"] = True
if "halal" in question.lower():
criteria["halal"] = True
if "kosher" in question.lower():
criteria["kosher"] = True
if "vegetarian" in question.lower():
criteria["vegetarian"] = True
# Extract price and cuisine
if "low" in question.lower():
criteria["price"] = "Low"
elif "moderate" in question.lower():
criteria["price"] = "Moderate"
elif "high" in question.lower():
criteria["price"] = "High"
if any(cuisine in question.lower() for cuisine in ["american", "indian", "middle eastern", "chinese", "italian", "thai", "hawaiian-korean", "japanese", "ethiopian", "pakistani", "mexican", "ghanaian", "vietnamese", "filipino", "spanish", "turkish"]):
criteria["cuisine"] = next(cuisine for cuisine in ["american", "indian", "middle eastern", "chinese", "italian", "thai", "hawaiian-korean", "japanese", "ethiopian", "pakistani", "mexican", "ghanaian", "vietnamese", "filipino", "spanish", "turkish"] if cuisine in question.lower())
response = generate_recommendation(criteria)
else:
relevant_segment = find_relevant_segment(question, segments)
if not relevant_segment:
return "Could not find specific information. Please refine your question."
response = generate_response(question, relevant_segment)
return response
# Define the welcome message and specific topics the chatbot can provide information about
welcome_message = """
# Welcome to Ethical Eats Explorer!
## Your AI-driven assistant for restaurant recs in Seattle. Created by Saranya, Cindy, and Liana of the 2024 Kode With Klossy Seattle Camp.
"""
topics = """
### Please give me your restaurant preferences:
- Dietary Restrictions
- Cuisine Preferences (optional)
- Cuisines: American, Indian, Middle Eastern, Chinese, Italian, Thai, Hawaiian-Korean, Japanese, Ethiopian, Pakistani, Mexican, Ghanaian, Vietnamese, Filipino, Spanish, Turkish
- Budget Preferences (Low: $0 - $20, Moderate: $20 - $30, High: $30+ - per person)
Please send your message in the format: "Could you give me a (cuisine) restaurant with (dietary restriction) options that is (budget) budget?"
"""
# Setup the Gradio Blocks interface with custom layout components
with gr.Blocks(theme='JohnSmith9982/small_and_pretty') as demo:
gr.Image("eeepic.png", show_label = False, show_share_button = False, show_download_button = False)
gr.Markdown(welcome_message) # Display the formatted welcome message
with gr.Row():
with gr.Column():
gr.Markdown(topics) # Show the topics on the left side
with gr.Row():
with gr.Column():
question = gr.Textbox(label="Your question", placeholder="Give me your information...")
answer = gr.Textbox(label="Explorer's Response", placeholder="Explorer will respond here...", interactive=False, lines=10)
submit_button = gr.Button("Submit")
submit_button.click(fn=query_model, inputs=question, outputs=answer)
# Launch the Gradio app to allow user interaction
demo.launch(share=True)