|
import gradio as gr |
|
from sentence_transformers import SentenceTransformer, util |
|
import openai |
|
import os |
|
|
|
os.environ["TOKENIZERS_PARALLELISM"] = "false" |
|
openai.api_key = os.environ["OPENAI_API_KEY"] |
|
|
|
|
|
filename = "output_topic_details.txt" |
|
retrieval_model_name = 'output/sentence-transformer-finetuned/' |
|
|
|
|
|
system_message = "You are a restaurant recommending chatbot that suggests one restaurant in Seattle from the restaurant database based on the criteria the user provides." |
|
|
|
|
|
messages = [{"role": "system", "content": system_message}] |
|
|
|
|
|
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}" |
|
|
|
|
|
restaurants = [ |
|
{ |
|
"name": "Saffron Grill", |
|
"cuisine": "Middle Eastern", |
|
"price": "Moderate", |
|
"gluten_free": True, |
|
"vegan": False, |
|
"lactose_intolerant": True, |
|
"pescatarian": True, |
|
"allergen_friendly": False, |
|
"halal": True, |
|
"kosher": False, |
|
"vegetarian": True, |
|
"website": "https://www.saffrongrill.com" |
|
}, |
|
{ |
|
"name": "Tasty Thai", |
|
"cuisine": "Thai", |
|
"price": "Low", |
|
"gluten_free": False, |
|
"vegan": True, |
|
"lactose_intolerant": True, |
|
"pescatarian": True, |
|
"allergen_friendly": True, |
|
"halal": False, |
|
"kosher": False, |
|
"vegetarian": True, |
|
"website": "https://www.tastythai.com" |
|
}, |
|
|
|
] |
|
|
|
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) |
|
return "\n".join(recommendations) |
|
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(): |
|
|
|
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 |
|
|
|
|
|
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 |
|
|
|
|
|
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?" |
|
""" |
|
|
|
|
|
with gr.Blocks(theme='JohnSmith9982/small_and_pretty') as demo: |
|
gr.Markdown(welcome_message) |
|
with gr.Row(): |
|
with gr.Column(): |
|
gr.Markdown(topics) |
|
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) |
|
|
|
|
|
demo.launch(share=True) |
|
|