|
|
import pickle |
|
|
import streamlit as st |
|
|
import numpy as np |
|
|
import pandas as pd |
|
|
import re |
|
|
from tensorflow.keras.models import load_model |
|
|
from tensorflow.keras.preprocessing.sequence import pad_sequences |
|
|
from nltk.corpus import stopwords |
|
|
from sklearn.preprocessing import StandardScaler |
|
|
import nltk |
|
|
import time |
|
|
|
|
|
|
|
|
nltk.download('stopwords') |
|
|
|
|
|
|
|
|
model = load_model("./best_model.keras") |
|
|
|
|
|
|
|
|
with open("./tokenizer.pkl", "rb") as f: |
|
|
tokenizer = pickle.load(f) |
|
|
|
|
|
|
|
|
if not hasattr(tokenizer, 'texts_to_sequences'): |
|
|
raise ValueError("Loaded tokenizer is not a valid Keras Tokenizer object.") |
|
|
|
|
|
|
|
|
MAX_SEQUENCE_LENGTH = 100 |
|
|
|
|
|
|
|
|
def simple_tokenizer(text): |
|
|
text = text.lower() |
|
|
text = re.sub(r'[^a-zA-Z\s]', '', text) |
|
|
tokens = text.split() |
|
|
return tokens |
|
|
|
|
|
|
|
|
def preprocess_input_review(review_text): |
|
|
tokens = simple_tokenizer(review_text) |
|
|
stop_words = set(stopwords.words('english')) |
|
|
tokens = [word for word in tokens if word not in stop_words] |
|
|
processed_review = ' '.join(tokens) |
|
|
return processed_review |
|
|
|
|
|
|
|
|
def time_to_minutes(time_str): |
|
|
if not time_str or pd.isna(time_str): |
|
|
return 0 |
|
|
hours, minutes = 0, 0 |
|
|
if 'H' in time_str: |
|
|
parts = time_str.split('H') |
|
|
hours = int(parts[0]) if parts[0].isdigit() else 0 |
|
|
time_str = parts[1] if len(parts) > 1 else '' |
|
|
if 'M' in time_str and time_str.split('M')[0].isdigit(): |
|
|
minutes = int(time_str.split('M')[0]) |
|
|
return hours * 60 + minutes |
|
|
|
|
|
|
|
|
def predict_menu_inclusion(food_name, review_text, cook_time, prep_time, total_time, protein, carbs, fat): |
|
|
|
|
|
processed_review = preprocess_input_review(review_text) |
|
|
|
|
|
|
|
|
review_sequence = tokenizer.texts_to_sequences([processed_review]) |
|
|
padded_review = pad_sequences(review_sequence, maxlen=MAX_SEQUENCE_LENGTH) |
|
|
|
|
|
|
|
|
numerical_features = np.array([[time_to_minutes(cook_time), |
|
|
time_to_minutes(prep_time), |
|
|
time_to_minutes(total_time), |
|
|
protein, carbs, fat]]) |
|
|
|
|
|
|
|
|
scaler = StandardScaler() |
|
|
numerical_features = scaler.fit_transform(numerical_features) |
|
|
|
|
|
|
|
|
predicted_rating = model.predict([padded_review, numerical_features]).flatten()[0] |
|
|
|
|
|
|
|
|
include_on_menu = predicted_rating > 3.5 |
|
|
|
|
|
return { |
|
|
"FoodName": food_name, |
|
|
"PredictedRating": round(predicted_rating, 2), |
|
|
"IncludeOnMenu": include_on_menu |
|
|
} |
|
|
|
|
|
|
|
|
st.set_page_config(page_title="Recipe Rating & Menu Optimization", layout="wide") |
|
|
|
|
|
st.title("๐ฒ๐ Recipe Rating & Menu Optimization ๐") |
|
|
st.markdown( |
|
|
""" |
|
|
Welcome to the **Recipe Rating & Menu Optimization** app! ๐ |
|
|
This tool uses cutting-edge **AI and machine learning** ๐ง to help chefs, restaurateurs, and food enthusiasts ๐ฝ๏ธ predict recipe ratings and decide if a dish deserves a place on the menu. ๐ |
|
|
|
|
|
|
|
|
Let's get started and create culinary magic! โจ |
|
|
""" |
|
|
) |
|
|
|
|
|
|
|
|
st.sidebar.header("๐ Enter Recipe Details") |
|
|
food_name = st.sidebar.text_input("๐ด Food Name", value="Paneer Butter Masala") |
|
|
review_text = st.sidebar.text_area("๐ Review Text", value="This dish is delicious, rich in flavor, and a favorite among customers!") |
|
|
cook_time = st.sidebar.text_input("โณ Cooking Time (e.g., 15M or 2H30M)", value="30M") |
|
|
prep_time = st.sidebar.text_input("๐ Preparation Time (e.g., 15M or 1H15M)", value="15M") |
|
|
total_time = st.sidebar.text_input("๐
Total Time (e.g., 45M or 1H45M)", value="45M") |
|
|
protein = st.sidebar.number_input("๐ช Protein (grams)", min_value=0.0, step=1.0, value=20.0) |
|
|
carbs = st.sidebar.number_input("๐ Carbohydrates (grams)", min_value=0.0, step=1.0, value=10.0) |
|
|
fat = st.sidebar.number_input("๐ Fat (grams)", min_value=0.0, step=1.0, value=15.0) |
|
|
|
|
|
if st.sidebar.button("๐ฎ Predict"): |
|
|
result = predict_menu_inclusion(food_name, review_text, cook_time, prep_time, total_time, protein, carbs, fat) |
|
|
predicted_rating = result["PredictedRating"] |
|
|
include_on_menu = result["IncludeOnMenu"] |
|
|
|
|
|
|
|
|
bar_color = "green" if include_on_menu else "red" |
|
|
progress_percentage = int(predicted_rating * 20) |
|
|
|
|
|
|
|
|
st.markdown( |
|
|
f""" |
|
|
<div style=" |
|
|
width: 100%; |
|
|
background-color: #ddd; |
|
|
border-radius: 10px; |
|
|
margin-bottom: 15px; |
|
|
"> |
|
|
<div style=" |
|
|
width: {progress_percentage}%; |
|
|
height: 25px; |
|
|
background-color: {bar_color}; |
|
|
border-radius: 10px; |
|
|
text-align: center; |
|
|
color: white; |
|
|
line-height: 25px; |
|
|
font-weight: bold; |
|
|
animation: growBar 2s; |
|
|
"> |
|
|
{progress_percentage}% |
|
|
</div> |
|
|
</div> |
|
|
<style> |
|
|
@keyframes growBar {{ |
|
|
from {{ width: 0%; }} |
|
|
to {{ width: {progress_percentage}%; }} |
|
|
}} |
|
|
</style> |
|
|
""", |
|
|
unsafe_allow_html=True, |
|
|
) |
|
|
|
|
|
|
|
|
st.subheader("Prediction Results") |
|
|
st.markdown(f"**๐ด Food Name:** {result['FoodName']}") |
|
|
st.markdown(f"**โญ Predicted Rating:** {result['PredictedRating']:.1f}") |
|
|
|
|
|
st.markdown( |
|
|
f"**๐ฝ๏ธ Include on Menu:** " |
|
|
f"<span style='color: {'green' if include_on_menu else 'red'}; font-weight: bold;'>" |
|
|
f"{'Yes' if include_on_menu else 'No'}</span>", |
|
|
unsafe_allow_html=True, |
|
|
) |
|
|
|
|
|
|